<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>Hexo</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description">
<meta property="og:type" content="website">
<meta property="og:title" content="Hexo">
<meta property="og:url" content="http://yoursite.com/page/5/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:description">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Hexo">
<meta name="twitter:description">
  
    <link rel="alternative" href="/atom.xml" title="Hexo" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.png">
  
  <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  <link rel="stylesheet" href="/css/style.css" type="text/css">
  

</head>
<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/" id="logo">Hexo</a>
      </h1>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/">Home</a>
        
          <a class="main-nav-link" href="/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" results="0" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="http://yoursite.com"></form>
      </div>
    </div>
  </div>
</header>
      <div class="outer">
        <section id="main">
  
    <article id="post-杂项/1.MQTT协议" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2016/01/12/杂项/1.MQTT协议/" class="article-date">
  <time datetime="2016-01-12T12:41:00.000Z" itemprop="datePublished">2016-01-12</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/杂项/">杂项</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2016/01/12/杂项/1.MQTT协议/">MQTT协议</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7279_u70B9"><a href="#u7279_u70B9" class="headerlink" title="特点"></a>特点</h2><p>　　MQTT（Message Queue Telemetry Transport）：遥测传输协议，提供订阅/发布模式，更为简约、轻量，易于使用。针对受限环境（带宽低、网络延迟高、网络通信不稳定），可以简单概括为物联网打造，官方总结特点如下：<br>　　1.使用发布/订阅消息模式，提供一对多的消息发布，解除应用程序耦合<br>　　2. 对负载内容屏蔽的消息传输<br>　　3. 使用 TCP/IP 提供网络连接<br>　　4. 有三种消息发布服务质量（QoS:Quality of Service）：<br>　　　　至多一次：消息发布完全依赖底层 TCP/IP 网络，会发生消息丢失或重复<br>　　　　至少一次：确保消息到达，但消息重复可能会发生<br>　　　　只有一次：确保消息到达一次，可以用于在计费系统中，消息重复或丢失会导致不正确的结果<br>　　5. 小型传输，开销很小（固定长度的头部是 2 字节），协议交换最小化，以降低网络流量<br>　　6. 使用 Last Will 和 Testament 特性通知有关各方客户端异常中断的机制</p>
<h2 id="u534F_u8BAE_u683C_u5F0F"><a href="#u534F_u8BAE_u683C_u5F0F" class="headerlink" title="协议格式"></a>协议格式</h2><p>　　简单点说，mqtt协议包含三个部分，分别为：固定头部、可变头部和消息体。每个部分存储的元数据信息如下：</p>
<h4 id="1-__u56FA_u5B9A_u5934_u90E8"><a href="#1-__u56FA_u5B9A_u5934_u90E8" class="headerlink" title="1. 固定头部"></a>1. 固定头部</h4><p>　　mqtt的固定头部为两个字节长度，结构如下图所示：<img src="/images/mqtt-head1.jpg" alt="mqtt-head1.jpg"><br>　　第一个字节(8位)被分成了四个部分，高四位存储了消息的类型，使用4位二进制表示，可代表16种消息类型，除去0和15位置属于保留待用，共14种消息事件类型。：</p>
<h5 id="1-1_Message_Type"><a href="#1-1_Message_Type" class="headerlink" title="1.1 Message Type"></a>1.1 Message Type</h5><table>
<thead>
<tr>
<th style="text-align:left">Mnemonic</th>
<th style="text-align:center">Enumeration</th>
<th style="text-align:left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">Reserved</td>
<td style="text-align:center">0</td>
<td style="text-align:left">保留</td>
</tr>
<tr>
<td style="text-align:left">CONNECT</td>
<td style="text-align:center">1</td>
<td style="text-align:left">连接请求</td>
</tr>
<tr>
<td style="text-align:left">CONNACK</td>
<td style="text-align:center">2</td>
<td style="text-align:left">连接回执</td>
</tr>
<tr>
<td style="text-align:left">PUBLISH</td>
<td style="text-align:center">3</td>
<td style="text-align:left">发送消息</td>
</tr>
<tr>
<td style="text-align:left">PUBACK</td>
<td style="text-align:center">4</td>
<td style="text-align:left">发送回执</td>
</tr>
<tr>
<td style="text-align:left">PUBREC</td>
<td style="text-align:center">5</td>
<td style="text-align:left">Publish Received (assured delivery part 1)</td>
</tr>
<tr>
<td style="text-align:left">PUBREL</td>
<td style="text-align:center">6</td>
<td style="text-align:left">Publish Release (assured delivery part 2)</td>
</tr>
<tr>
<td style="text-align:left">PUBCOMP</td>
<td style="text-align:center">7</td>
<td style="text-align:left">Publish Complete (assured delivery part 3)</td>
</tr>
<tr>
<td style="text-align:left">SUBSCRIBE</td>
<td style="text-align:center">8</td>
<td style="text-align:left">客户端订阅请求</td>
</tr>
<tr>
<td style="text-align:left">SUBACK</td>
<td style="text-align:center">9</td>
<td style="text-align:left">订阅请求回执</td>
</tr>
<tr>
<td style="text-align:left">UNSUBSCRIBE</td>
<td style="text-align:center">10</td>
<td style="text-align:left">取消订阅请求</td>
</tr>
<tr>
<td style="text-align:left">UNSUBACK</td>
<td style="text-align:center">11</td>
<td style="text-align:left">取消订阅回执</td>
</tr>
<tr>
<td style="text-align:left">PINGREQ</td>
<td style="text-align:center">12</td>
<td style="text-align:left">心跳</td>
</tr>
<tr>
<td style="text-align:left">PINGRESP</td>
<td style="text-align:center">13</td>
<td style="text-align:left">心跳响应</td>
</tr>
<tr>
<td style="text-align:left">DISCONNECT</td>
<td style="text-align:center">14</td>
<td style="text-align:left">连接断开</td>
</tr>
<tr>
<td style="text-align:left">Reserved</td>
<td style="text-align:center">15</td>
<td style="text-align:left">保留</td>
</tr>
</tbody>
</table>
<h5 id="1-2_DUP_flag_28_u6253_u5F00_u6807_u5FD7_29"><a href="#1-2_DUP_flag_28_u6253_u5F00_u6807_u5FD7_29" class="headerlink" title="1.2 DUP flag(打开标志)"></a>1.2 DUP flag(打开标志)</h5><p>　　保证消息可靠传输，默认为0，只占用一个字节，表示第一次发送。不能用于检测消息重复发送等。只适用于客户端或服务器端尝试重发PUBLISH, PUBREL, SUBSCRIBE 或 UNSUBSCRIBE消息，注意需要满足以下条件：当QoS &gt; 0，消息需要回复确认</p>
<h5 id="1-3_QoS_28Quality_of_Service_2C_u670D_u52A1_u8D28_u91CF_29"><a href="#1-3_QoS_28Quality_of_Service_2C_u670D_u52A1_u8D28_u91CF_29" class="headerlink" title="1.3 QoS(Quality of Service,服务质量)"></a>1.3 QoS(Quality of Service,服务质量)</h5><p>　　使用两个二进制表示PUBLISH类型消息：</p>
<table>
<thead>
<tr>
<th style="text-align:left">QoS value</th>
<th style="text-align:center">bit 2</th>
<th style="text-align:center">bit 1</th>
<th style="text-align:left">Description</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">0</td>
<td style="text-align:center">0</td>
<td style="text-align:center">0</td>
<td style="text-align:left">至多一次</td>
<td>发完即丢弃</td>
<td>&lt;=1</td>
</tr>
<tr>
<td style="text-align:left">1</td>
<td style="text-align:center">0</td>
<td style="text-align:center">1</td>
<td style="text-align:left">至少一次</td>
<td>需要确认回复</td>
<td>&gt;=1</td>
</tr>
<tr>
<td style="text-align:left">2</td>
<td style="text-align:center">1</td>
<td style="text-align:center">0</td>
<td style="text-align:left">只有一次</td>
<td>需要确认回复</td>
<td>=1</td>
</tr>
<tr>
<td style="text-align:left">3</td>
<td style="text-align:center">1</td>
<td style="text-align:center">1</td>
<td style="text-align:left">待用，保留位置</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<h5 id="1-4_RETAIN_28_u4FDD_u6301_29"><a href="#1-4_RETAIN_28_u4FDD_u6301_29" class="headerlink" title="1.4 RETAIN(保持)"></a>1.4 RETAIN(保持)</h5><p>　　仅针对PUBLISH消息，不同值表示不同含义：<br>　　1：表示发送的消息需要一直持久保存（不受服务器重启影响），不但要发送给当前的订阅者，并且以后新来的订阅了此Topic name的订阅者会马上得到推送。备注：新来乍到的订阅者，只会取出最新的一个RETAIN flag = 1的消息推送。<br>　　0：仅仅为当前订阅者推送此消息。假如服务器收到一个空消息体(zero-length payload)、RETAIN = 1、已存在Topic name的PUBLISH消息，服务器可以删除掉对应的已被持久化的PUBLISH消息。</p>
<h5 id="1-5_Remaining_Length_28_u5269_u4F59_u957F_u5EA6_29"><a href="#1-5_Remaining_Length_28_u5269_u4F59_u957F_u5EA6_29" class="headerlink" title="1.5 Remaining Length(剩余长度)"></a>1.5 Remaining Length(剩余长度)</h5><p>　　该字节存储了消息剩余的byte(字节)数，包含固定头部之后的<strong>可变头部长度</strong>和<strong>消息体长度</strong>。<br>　　单个字节最大值为01111111，16进制为0x7F，10进制为127。单个字节为什么不能是11111111（0xFF）呢？因为MQTT协议规定，<strong>第八位（最高位）若为1，则表示还有后续字节存在</strong>。同时MQTT协议最多允许4个字节表示剩余长度。那么最大长度为：0xFF,0xFF,0xFF,0x7F，二进制表示为:11111111,11111111,11111111,01111111，去掉首位后为：1111111111111111111111111111(共28个1)，转换成十进制为268435455 byte=261120KB=256MB=0.25GB。下面我们看看可变头部的内容！</p>
<h4 id="2-__u53EF_u53D8_u5934_u90E8"><a href="#2-__u53EF_u53D8_u5934_u90E8" class="headerlink" title="2. 可变头部"></a>2. 可变头部</h4><p>　　可变头部中包含了消息的元数据。可变头部包含了协议名称、版本号、连接标志、用户授权和心跳时间等内容，这部分和后面要讲到的CONNECT消息类型有重复，暂时略过！</p>
<h5 id="2-1__u6D88_u606F_u6807_u8BC6_u7B26/_u6D88_u606FID"><a href="#2-1__u6D88_u606F_u6807_u8BC6_u7B26/_u6D88_u606FID" class="headerlink" title="2.1 消息标识符/消息ID"></a>2.1 消息标识符/消息ID</h5><p>　　固定头中的QoS level标志值为1或2时才会在：PUBLISH，PUBACK，PUBREC，PUBREL，PUBCOMP，SUBSCRIBE，SUBACK，UNSUBSCRIBE，UNSUBACK等消息的可变头中出现。<br>　　一个16位无符号位的short类型值（值不能为 0，0做保留作为无效的消息ID），仅仅要求在一个特定方向（服务器发往客户端为一个方向，客户端发送到服务器端为另一个方向）的通信消息中必须唯一。比如客户端发往服务器，有可能存在服务器发往客户端会同时存在重复，但不碍事。<br>　　可变头部中，需要两个字节的顺序是MSB(Most Significant Bit) LSB(Last/Least Significant Bit)，翻译成中文就是，最高有效位，最低有效位。最高有效位在最低有效位左边/上面，表示这是一个大端字节/网络字节序，符合人的阅读习惯，高位在最左边。<img src="/images/bigindian.jpg" alt="bigindian.jpg"><br>　　但凡如此表示的，都可以视为一个16位无符号short类型整数，两个字节表示。在JAVA中处理比较简单：DataInputStream.readUnsignedShort 或者 in.read() * 0xFF + in.read();最大长度可为： 65535</p>
<h4 id="3-_Playload/_u6D88_u606F_u4F53/_u8D1F_u8377"><a href="#3-_Playload/_u6D88_u606F_u4F53/_u8D1F_u8377" class="headerlink" title="3. Playload/消息体/负荷"></a>3. Playload/消息体/负荷</h4><p>　　消息体主要是为配合固定/可变头部命令（比如CONNECT可变头部User name标记若为1，则需要在消息体中附加用户名称字符串）而存在。<br>　　CONNECT/SUBSCRIBE/SUBACK/PUBLISH等消息有消息体。PUBLISH的消息体以二进制形式对待。<br>　　MQTT协议只允许在PUBLISH类型消息体中使用自定义特性，在固定/可变头部想加入自定义私有特性，就免了吧。这也是为了协议免于流于形式，变得很分裂也为了兼顾现有客户端等。比如支持压缩等，那就可以在Playload中定义数据支持，在应用中进行读取处理。</p>
<h4 id="4-_UTF-8_u7F16_u7801"><a href="#4-_UTF-8_u7F16_u7801" class="headerlink" title="4. UTF-8编码"></a>4. UTF-8编码</h4><p>　　有关字符串，MQTT采用的是修改版的UTF-8编码，一般形式为如下，需要牢记：<img src="/images/mqtt-uft8.jpg" alt="mqtt-uft8.jpg"><br>　　比如JAVA，使用writeUTF()方法写入一串文字“OTWP”，头两个字节为一个完整的无符号数字，代表字符串字节长度，后面四个字节才是字符串真正的长度，共六个字节。<br>　　MQTT无论是可变头部还是消息体中，只要是字符串部分，都是采用了修改版的UTF-8编码，读取和写入，借助DataInputStream/DataOutputStream的帮助，一行语句，略去了手动处理的麻烦。</p>
<h2 id="u79FB_u52A8_u4E92_u8054_u7F51_u4F7F_u7528"><a href="#u79FB_u52A8_u4E92_u8054_u7F51_u4F7F_u7528" class="headerlink" title="移动互联网使用"></a>移动互联网使用</h2><p>　　手机等终端在弱网络环境下丢包情况会非常明显，连接MQTT Server成功率很低。相比单纯的请求-相应模型的HTTP，其成功率会比MQTT订阅成功高很多。<br>　　手机终端在每次TCP断开或断网后，会即刻发起TCP重连，连接成功，会重复以前步骤依次发送连接命令（CONNECT），订阅命令（SUBSCRIBLE），表明上看，这些过程没有任何问题，但问题就在于从终端成功建立到服务器的连接，到发送订阅命令，在弱网情况下，这个过程将会变得很昂贵：<strong>从TCP建立开始的三次握手到完整的订阅命令发送完毕，考虑到TCP堆栈的每次接收数据方响应ACK，这中间终端和服务器端至少产生了10次数据交互。</strong></p>
<h2 id="u534F_u8BAE_u4F18_u5316"><a href="#u534F_u8BAE_u4F18_u5316" class="headerlink" title="协议优化"></a>协议优化</h2><p>　　1. 客户端连接成功，服务端回执连接成功状态等过程可以省略<br>　　2. 消息头包含有过多的元数据信息，如QoS等，可以省略<br>　　3. 心跳命令PINGREQ/PINGREQ可以做到一个字节传输，节省一个字节</p>
<h2 id="u53C2_u8003_u94FE_u63A5"><a href="#u53C2_u8003_u94FE_u63A5" class="headerlink" title="参考链接"></a>参考链接</h2><p><a href="http://www.blogjava.net/yongboy/archive/2014/02/07/409587.html" target="_blank" rel="external">http://www.blogjava.net/yongboy/archive/2014/02/07/409587.html</a><br><a href="http://www.blogjava.net/yongboy/archive/2014/12/12/421331.html" target="_blank" rel="external">http://www.blogjava.net/yongboy/archive/2014/12/12/421331.html</a><br><a href="http://www.cnblogs.com/caca/p/mqtt.html" target="_blank" rel="external">http://www.cnblogs.com/caca/p/mqtt.html</a><br><a href="http://www.blogjava.net/yongboy/category/54835.html" target="_blank" rel="external">http://www.blogjava.net/yongboy/category/54835.html</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2016/01/12/杂项/1.MQTT协议/" data-id="cijzzpv0n000l1cfse3gqk6bo" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/mqtt/">mqtt</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-mq/6.Kafka系列之ZeroCopy" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2016/01/12/mq/6.Kafka系列之ZeroCopy/" class="article-date">
  <time datetime="2016-01-12T09:56:00.000Z" itemprop="datePublished">2016-01-12</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/mq/">mq</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2016/01/12/mq/6.Kafka系列之ZeroCopy/">Kafka系列三之ZeroCopy</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>　　从kafka设计的特点可以看出网络操作和文件操作非常频繁，为了提高效率，kafka在push或者poll消息的时候通常会分成组也就是先buffer一下再批量的进行操作。<br>　　与此同时为了更好地效率，kafka使用了linux系统提供的sendfile系统。在理解sendfile之前有必要了解一下传统的文件操作或者socket是怎么处理的，假设需要把本地磁盘的文件通过socket发送给远端，首先需要read到内存然后通过socket发送，整个过程可以用下面一张图表示：<img src="/images/zero-copy.gif" alt="zero-copy.gif"><img src="/images/zero-copy2.gif" alt="zero-copy2.gif"><br>　　linux系统的内核态和用户态分别对应上图的kernel context和appliaction context，在这两种形态之间发生切换是很消耗资源的，但是一个发送文件的过程确发生了四次这样的切换。<br>　　数据读取过程：首先由应用程序发出read请求，切换到内核态，由内核完成数据的读取，然后返回给应用，切换到用户态，此时发生两次切换和数据的两次拷贝DMA copy和CPU copy。<br>　　数据发送过程：发送的过程同样发生上下文的两次切换和数据的两次拷贝，来来回回发生了很多次的拷贝，zero-copy的出现就是消除不必要的copy动作。java已经提供了类似的api比如FileChannel的transferTo()，类似的api在高性能的通讯框架中应用的很广泛比如Netty。下面两张图描述了早期zero-copy的流程：<img src="/images/zero-copy3.gif" alt="zero-copy3.gif"><img src="/images/zero-copy4.gif" alt="zero-copy4.gif"><br>　　transferTo()方法免去了内核到用户态数据的copy，从而直接将读取到的buffer传输到socket buffer，拷贝过程省去了一次，上下文切换少了两次。但是事情到此还没有结束，后面经过代码的优化数据复制的次数还能减少，只是2.4版本以上的linux才支持，优化后的流程类似下面：<img src="/images/zero-copy5.gif" alt="zero-copy5.gif"><br>　　上图内核的操作少了一步，原先需要内核将read buffer的数据传输到socket buffer，然后由DMA拷贝到NIC buffer由网卡发送，现在是在read buffer加上一些描述符，从而由DMA直接拷贝read buffer对应的发送数据到NIC buffer，整个拷贝过程减少到了两次，性能大大的提高了。</p>
<h2 id="u53C2_u8003_u5730_u5740"><a href="#u53C2_u8003_u5730_u5740" class="headerlink" title="参考地址"></a>参考地址</h2><p><a href="http://blog.chinaunix.net/uid-20196318-id-2420884.html" target="_blank" rel="external">http://blog.chinaunix.net/uid-20196318-id-2420884.html</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2016/01/12/mq/6.Kafka系列之ZeroCopy/" data-id="cijzzpv9f00841cfs1wnmx0dr" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/kafka/">kafka</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/mq/">mq</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-mq/5.Kafka系列之安装使用" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2016/01/12/mq/5.Kafka系列之安装使用/" class="article-date">
  <time datetime="2016-01-12T09:50:00.000Z" itemprop="datePublished">2016-01-12</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/mq/">mq</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2016/01/12/mq/5.Kafka系列之安装使用/">Kafka系列二之安装使用</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="Windows_u4E0B_u5355_u673A_u5B89_u88C5"><a href="#Windows_u4E0B_u5355_u673A_u5B89_u88C5" class="headerlink" title="Windows下单机安装"></a>Windows下单机安装</h2><p>　　1. 安装java并设置环境变量。下载kafka_2.9.1-0.8.2.1.tgz并解压至d:\prg\kafka，修改配置文件zookeeper.properties和server.properties，调整日志的存储路径</p>
<p>　　2. 启动zookeeper服务器<br>D:\prg\kafka&gt;bin\windows\zookeeper-server-start.bat config\zookeeper.properties</p>
<p>　　3. 启动kafka服务器<br>D:\prg\kafka&gt;bin\windows\kafka-server-start.bat config\server.properties</p>
<p>　　4. 创建topic<br>D:\prg\kafka&gt;bin\windows\kafka-topics.bat –create –zookeeper localhost:2181 –replication-factor 1 –partitions 1 –topic test</p>
<p>　　5. 查看topic<br>D:\prg\kafka&gt;bin\windows\kafka-topics.bat –list –zookeeper localhost:2181</p>
<p>　　6. 发送message，参数topic和broker-list是必须的，通过终端输出可以看出，(配置文件无用)<br>D:\prg\kafka&gt;bin\windows\kafka-console-producer.bat config\producer.properties –topic test –broker-list localhost:9092<br>成功后自动进入交互状态，输入内容后再输入英文分号;，下面的启动的消费者可以自动显示数据</p>
<p>　　7. 启动consumer<br>D:\prg\kafka&gt;bin\windows\kafka-console-consumer.bat config\consumer.properties –zookeeper localhost:2181 –topic test</p>
<h2 id="linux_u4E0B_u96C6_u7FA4_u90E8_u7F72"><a href="#linux_u4E0B_u96C6_u7FA4_u90E8_u7F72" class="headerlink" title="linux下集群部署"></a>linux下集群部署</h2><p>　　1. 在三台机器上安装jdk，zookeeper集群</p>
<p>　　2. 每台机器配置如下:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">$ cat /etc/hosts</span><br><span class="line">...</span><br><span class="line"><span class="comment"># zookeeper hostnames:</span></span><br><span class="line"><span class="number">192.168</span>.<span class="number">8.182</span>      zk1</span><br><span class="line"><span class="number">192.168</span>.<span class="number">8.183</span>      zk2</span><br><span class="line"><span class="number">192.168</span>.<span class="number">8.184</span>      zk3</span><br></pre></td></tr></table></figure></p>
<p>　　3. 配置环境变量<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> JAVA_HOME=/usr/<span class="built_in">local</span>/java/jdk1.<span class="number">7.0</span>_60</span><br><span class="line"><span class="built_in">export</span> CLASSPATH=.:<span class="variable">$JAVA_HOME</span>/lib:<span class="variable">$CLASSPATH</span></span><br><span class="line"><span class="built_in">export</span> PATH=<span class="variable">$JAVA_HOME</span>/bin:<span class="variable">$JAVA_HOME</span>:<span class="variable">$PATH</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">export</span> ZOOKEEPER_HOME=/usr/<span class="built_in">local</span>/zookeeper-<span class="number">3.4</span>.<span class="number">6</span></span><br><span class="line"><span class="built_in">export</span> PATH=<span class="variable">$ZOOKEEPER_HOME</span>/bin:<span class="variable">$PATH</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">export</span> KAFKA_HOME=/usr/<span class="built_in">local</span>/kafka_2.<span class="number">9.2</span>-<span class="number">0.8</span>.<span class="number">2.1</span></span><br><span class="line"><span class="built_in">export</span> PATH=<span class="variable">$KAFKA_HOME</span>/bin:<span class="variable">$PATH</span></span><br></pre></td></tr></table></figure></p>
<p>　　4. centos1上配置$KAFKA_HOME/config/server.properties<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">broker.id=<span class="number">0</span></span><br><span class="line">port=<span class="number">9092</span></span><br><span class="line">host.name=centos1</span><br><span class="line"><span class="comment">#advertised.host.name=centos1</span></span><br><span class="line">...</span><br><span class="line">num.partitions=<span class="number">2</span></span><br><span class="line">...</span><br><span class="line">zookeeper.connect=<span class="number">192.168</span>.<span class="number">241.129</span>:<span class="number">2181</span>,<span class="number">192.168</span>.<span class="number">241.130</span>:<span class="number">2181</span>,<span class="number">192.168</span>.<span class="number">241.131</span>:<span class="number">2181</span></span><br><span class="line"><span class="comment">#日志和数据文件（包括其索引文件）存储目录</span></span><br><span class="line">log.dirs=/mapbar/kafka_2.<span class="number">9.1</span>-<span class="number">0.8</span>.<span class="number">2.1</span>/dataLogs</span><br></pre></td></tr></table></figure></p>
<p>　　5. centos2上配置$KAFKA_HOME/config/server.properties<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">broker.id=<span class="number">1</span></span><br><span class="line">port=<span class="number">9092</span></span><br><span class="line">host.name=centos2</span><br><span class="line"><span class="comment">#advertised.host.name=centos1</span></span><br><span class="line">...</span><br><span class="line">num.partitions=<span class="number">2</span></span><br><span class="line">...</span><br><span class="line">zookeeper.connect=<span class="number">192.168</span>.<span class="number">241.129</span>:<span class="number">2181</span>,<span class="number">192.168</span>.<span class="number">241.130</span>:<span class="number">2181</span>,<span class="number">192.168</span>.<span class="number">241.131</span>:<span class="number">2181</span></span><br></pre></td></tr></table></figure></p>
<p>　　6. centos3上配置$KAFKA_HOME/config/server.properties<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">broker.id=<span class="number">2</span></span><br><span class="line">port=<span class="number">9092</span></span><br><span class="line">host.name=centos3</span><br><span class="line"><span class="comment">#advertised.host.name=centos1</span></span><br><span class="line">...</span><br><span class="line">num.partitions=<span class="number">2</span></span><br><span class="line">...</span><br><span class="line">zookeeper.connect=<span class="number">192.168</span>.<span class="number">241.129</span>:<span class="number">2181</span>,<span class="number">192.168</span>.<span class="number">241.130</span>:<span class="number">2181</span>,<span class="number">192.168</span>.<span class="number">241.131</span>:<span class="number">2181</span></span><br></pre></td></tr></table></figure></p>
<p>3)启动zookeeper服务, 在zk1,zk2,zk3上分别运行：<br>$ zkServer.sh start</p>
<p>4)后台启动kafka服务, 在zk1,zk2,zk3上分别运行：<br>$ kafka-server-start.sh $KAFKA_HOME/config/server.properties &amp;</p>
<p>5) 新建一个TOPIC(replication-factor=num of brokers)<br>$ kafka-topics.sh –create –topic test –replication-factor 3 –parti tions 2 –zookeeper 192.168.241.129:2181,192.168.241.130:2181,192.168.241.131:2181 </p>
<p>6)假设我们在zk2上，开一个终端，发送消息至kafka（zk2模拟producer）<br>$ kafka-console-producer.sh –broker-list zk1:9092 –sync –topic test<br>在发送消息的终端输入：Hello Kafka</p>
<p>7)假设我们在zk3上，开一个终端，显示消息的消费（zk3模拟consumer）（如果配置的zk集群，也只需要配置一个zookeeper参数）<br>$ kafka-console-consumer.sh –zookeeper zk1:2181 –topic test –from-beginning</p>
<h2 id="Java_u7F16_u7A0B"><a href="#Java_u7F16_u7A0B" class="headerlink" title="Java编程"></a>Java编程</h2><p>　　</p>
<p>　　</p>
<h2 id="u53C2_u8003_u5730_u5740"><a href="#u53C2_u8003_u5730_u5740" class="headerlink" title="参考地址"></a>参考地址</h2><p><a href="http://blog.chinaunix.net/uid-20196318-id-2420884.html" target="_blank" rel="external">http://blog.chinaunix.net/uid-20196318-id-2420884.html</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2016/01/12/mq/5.Kafka系列之安装使用/" data-id="cijzzpv9j008b1cfscw9ph30s" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/kafka/">kafka</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/mq/">mq</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-mq/4.Kafka系列之入门" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2016/01/12/mq/4.Kafka系列之入门/" class="article-date">
  <time datetime="2016-01-12T07:50:00.000Z" itemprop="datePublished">2016-01-12</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/mq/">mq</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2016/01/12/mq/4.Kafka系列之入门/">Kafka系列一之入门</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　Kafka是linkedin用于日志处理的分布式消息队列系统。linkedin的日志数据容量大，但对可靠性要求不高。当前很多的消息队列服务提供可靠交付保证，并默认是即时消费（不适合离线）。高可靠交付对linkedin的日志不是必须的，故可通过降低可靠性来提高性能，同时通过构建分布式的集群，允许消息在系统中累积，使得kafka同时支持离线和在线日志处理。Kafka的架构如下图所示<img src="/images/kafka-framework.png" alt="kafka-framework.png"></p>
<h2 id="u7279_u70B9"><a href="#u7279_u70B9" class="headerlink" title="特点"></a>特点</h2><p>　　1. 快速：单台kafka的broker实例能够支撑几千台机器每秒几百兆字节的读写，如果组成集群性能会更强进，从很多人的测试情况来看kafka的读写性能表现不输于当前流行的消息队，甚至领先很多<br>　　2. 扩展性：弹性透明的扩展，不需要停机，kafka的数据是分区的，可以分布在不同的server中，允许消费者并发的访问<br>　　3. 持久化：集群中的数据被持久化在磁盘上，以防止数据丢失<br>　　4. 分布式：kafka基于cluster-centric理念设计，有很好的容错性</p>
<h2 id="u6982_u5FF5"><a href="#u6982_u5FF5" class="headerlink" title="概念"></a>概念</h2><p>　　要熟悉kafka首先要了解一下kafka中的几个角色<br>　　1. Broker：kafka cluster便是由多个Broker组成，每个Broker代表kafka的一个实例（server）。一个集群由多个broker组成，一个broker可以容纳多个topic。<br>　　2. Producer——producer作为整个消息系统的输入部分，直接通过socket和Broker连接发布消息。<br>　　3. Consumer——consumer作为消息的消费者负责处理消息<br>　　无论是kafka集群，还是producer和consumer都依赖于zookeeper来保证系统可用性，zookeeper集群保存一些meta信息。毋庸置疑如何处理消息是一个消息系统核心的功能，比如生产者如何生产消息、消息怎么存储、消费者如何消费消息、消息的可靠性、重复性等等。</p>
<h2 id="Topic"><a href="#Topic" class="headerlink" title="Topic"></a>Topic</h2><p>　　topic是kafka抽象出来的一个概念，一个Topic可以被认为是一类消息，<strong>每个topic被分成多个partition</strong>。每个partition在存储层面是append log文件。任何发布到此partition的消息都会被直接追加到log文件的尾部，每条消息在文件中的位置称为offset（偏移量），offset为一个long型数字，它唯一标记一条消息。同一个partition中的消息是有序的，但是针对整个topic中的所有消息kafka不保证有序，这是因为每个partition只允许一个group（多个consumer构成一个group）中的一个consumer消费。
　　</p>
<h2 id="Partition"><a href="#Partition" class="headerlink" title="Partition"></a>Partition</h2><p>　　kafka中partition的概念非常的巧妙，在某种程度上消费者能够并发的消费消息就是因为partition的存在。<br>　　生产者将消息放入topic中，但是topic会被分成若干个partition（个数可配置），每个partition在物理上对应一个commit-log日志文件，每次发布消息都会以append的方式新增log，这是一个顺序写磁盘的过程性能上不会有太大的问题，同时在写日志前可以做buffer批量写磁盘。<br>　　同一个topic的不同partition会分布在不同的server上从而将访问压力分散开发，同时一个partitioin只允许同一个group中的某个消费者消费。关于哪个partition存放在哪个server上等一些meta信息全部存储在zookeeper上。<img src="/images/kafka-partition.png" alt="kafka-partition.png"></p>
<h2 id="Offset"><a href="#Offset" class="headerlink" title="Offset"></a>Offset</h2><p>　　kafka的存储文件都是按照offset.kafka来命名，用offset做名字的好处是方便查找。例如你想找位于2049的位置，只要找到2048.kafka的文件即可。当然the first offset就是00000000000.kafka</p>
<h2 id="u6D88_u606F_u5B58_u50A8"><a href="#u6D88_u606F_u5B58_u50A8" class="headerlink" title="消息存储"></a>消息存储</h2><p>　　kafka集群会保留所有已经发布过的消息，保存的时间可以通过配置文件指定，比如指定两天，则两天前发布的消息不管是否被消费都将被删除。从另一个角度看kafka允许消费者重复消费两天前的消息，这一点可能和很多消息系统不同，同时由于这个特性使得kafka也适合做离线的大数据分析。</p>
<h2 id="u5B58_u50A8_u7B56_u7565"><a href="#u5B58_u50A8_u7B56_u7565" class="headerlink" title="存储策略"></a>存储策略</h2><p>　　1. kafka以topic来进行消息管理，每个topic包含多个partition，每个part对应一个逻辑log，有多个segment组成。<br>　　2. 每个segment中存储多条消息（见下图），消息id由其逻辑位置决定，即从消息id可直接定位到消息的存储位置，避免id到位置的额外映射。<br>　　3. 每个part在内存中对应一个index，记录每个segment中的第一条消息偏移。<br>　　4.  发布者发到某个topic的消息会被均匀的分布到多个partition上（随机或根据用户指定的回调函数进行分布），broker收到发布消息往对应part的最后一个segment上添加该消息，当某个segment上的消息条数达到配置值或消息发布时间超过阈值时，segment上的消息会被flush到磁盘，<strong>只有flush到磁盘上的消息才能被订阅者订阅到</strong>，segment达到一定的大小后将不会再往该segment写数据，broker会创建新的segment。<br><img src="/images/kafka-segment.png" alt="kafka-segment.png"></p>
<h2 id="kafak_u548Czookeeper"><a href="#kafak_u548Czookeeper" class="headerlink" title="kafak和zookeeper"></a>kafak和zookeeper</h2><p>　　1. Broker端使用zookeeper用来注册broker信息并保持相关的元数据（topic，partition信息等）更新，以及监测partition leader存活性<br>　　2. Producer端使用zookeeper发现broker列表，以及和Topic的每个<strong>partition leader</strong>建立socket连接并发送消息<br>　　3. Consumer端使用zookeeper用来注册consumer信息，包括consumer消费的partition列表等，同时也用来发现broker列表，保证在添加或去除broker时，各broker间仍能自动实现负载均衡。并和partition leader建立socket连接，并获取消息</p>
<h2 id="Producer"><a href="#Producer" class="headerlink" title="Producer"></a>Producer</h2><p>　　producer负责生产消息，它会和topic中所有的partition leader（不同的broker实例）保持socket，然后直接将消息发送到对应的broker上，因此消息的负载均衡完全由producer侧来负责，默认kafka提供了轮询的方式。</p>
<h2 id="Consumer"><a href="#Consumer" class="headerlink" title="Consumer"></a>Consumer</h2><p>　　针对消息系统通常都会有两种模式：一种类似Queue，就是消息队列中的消息只会由一个消费者消费（<strong>点对点模式</strong>），另一种是<strong>订阅发布模式</strong>，只要订阅该消息的消费者都会收到广播的消息。<br>　　Kafka通过<strong>consumer group</strong>的概念来支持这两种方式。一个consumer group包含若干个consumer，topic中的消息只会被订阅该topic的group中的一个consumer消费，但是一个topic可以有多个consumer group。点对点模式：所有的消费者拥有相同的group；发布订阅模式：每个consumer都属于不同的consumer group<br>　　consumer消费消息的方式是通过改变offset来实现的，offset和partition一一对应并且保存在zookeeper上，consumer会定期的更新offset的值到zookeeper上。consumer默认支持reblance，该特性很好的达到了consumer的容错和扩展功能，举例来说：<img src="/images/kafka-consumer.png" alt="kafka-consumer.png"><br>　　上面就是reblance的过程，但是它有一个明显的缺点是消费者可能负载会不均衡，同时kafka建议partition的个数不能少于consumer的个数，如果不满足会出现有的consumer永远不会消费到消息。如果reblance算法不能满足使用需求，可以使用simple level api自己定义均衡算法，这种方式更灵活，同时应用的可能也更广泛。</p>
<h2 id="Push_u548CPull"><a href="#Push_u548CPull" class="headerlink" title="Push和Pull"></a>Push和Pull</h2><p>　　生产者负责push消息，<strong>消费者采用pull的方式拉取消息</strong>。push模式很难适应消费速率不同的消费者，因为消息发送速率是由broker决定的。push模式的目标是尽可能以最快速度传递消息，但是这样很容易造成consumer来不及处理消息（在rabbitmq中消费者消费的消息就是server push过来的。），典型的表现就是拒绝服务以及网络拥塞。而pull模式则可以根据consumer的消费能力以适当的速率消费消息。而在scribe和flume系统中则完全使用的是另外一种模式，这里不做介绍。<img src="/images/kafka-push-pull.png" alt="kafka-push-pull.png"></p>
<h2 id="u526F_u672C"><a href="#u526F_u672C" class="headerlink" title="副本"></a>副本</h2><p>　　kafka通过提供partition的复制策略来提高kafka的容错性，可以配置partition的副本个数，类似zookeeper的复制机制。<br>　　kafka针对partition的复制需要选出一个leader，由该leader负责partition的读写操作，其他的副本节点只是负责数据的同步。如果leader失效，将由其他follower来接管(成为新的leader)。<br>　　如果flower数据落后leader太多，leader会把该flower剔除。由于leader的server承载了全部的请求压力，因此从集群的整体考虑，有多少个partitions就意味着有多少个leader，kafka会将leader均横的分散在每个实例上，来确保整体的性能稳定。一个kafka集群各个节点间可能互为leader和flower。<img src="/images/kafka-partition-replication.png" alt="kafka-partition-replication.png"><br>　　上图中针对partition-2、partition-4，Broker-1是Broker-2的flower，同理针对partition-1、partition-3，Broker-2是Broker-1的flower，这种设计能够最大化的降低节点宕机带来的风险，同时采用选取leader的方式能够降低代码实现的复杂度，如果没有leader则需要考虑N*N的复制路径，一方面实现起来复杂另一方面效率也不一定会好</p>
<h2 id="u6D88_u606F_u5904_u7406_u673A_u5236"><a href="#u6D88_u606F_u5904_u7406_u673A_u5236" class="headerlink" title="消息处理机制"></a>消息处理机制</h2><p>　　1) at most once：最多一次，消息只发送一次，不管是否成功处理都不会重发。考虑消费者从broker获取到消息后然后触发commit动作，该动作会将offset的值写入到zk，下一次获取消息的时候会根据此偏移量获取，如果在commit后消费者处理消息失败则消费者永远不会再处理到该消息（offset以持久到zk）。<br>　　2) at least once:：消息至少发送一次，如果消息未能成功处理，可能会重发直到成功。考虑消费者从broker获取消息后先进行处理，等处理完在commit，但是在commit之前系统崩溃，这会导致系统下次还会再一次处理该消息，因此如果对消息的重复处理有严格的要求，比如扣费，则需要慎重使用该项，可以从接口设计方面改善，比如将扣费接口设计成幂等性的操作，从而避免消息重复发送造成的重复扣费。<br>　　3) exactly once：消息只会发送一次。kafka中并没有严格的去实现(基于2阶段提交，事务)，如果一定要做到exactly once ，就需要协调offset和实际操作的输出。精典的做法是引入两阶段提交，但是如果能让offset和操作输入存在同一个地方，会更简洁和通用。这种方式可能更好，因为许多输出系统可能不支持两阶段提交。比如，consumer拿到数据后可能把数据放到HDFS，如果把最新的offset和数据本身一起写到HDFS，那就可以保证数据的输出和offset的更新要么都完成，要么都不完成，间接实现exactly once。offset的处理可以使用simple level api自定义去完成。<br>　　两阶段提交的实现比较麻烦，它需要事务的协调者和事务的所有参与者之间经过多次消息的确认才能完成一个完成的事务提交动作，中间任何一步出错，所有参与者的事务都需要回滚。</p>
<h2 id="u53C2_u8003_u5730_u5740"><a href="#u53C2_u8003_u5730_u5740" class="headerlink" title="参考地址"></a>参考地址</h2><p><a href="http://blog.chinaunix.net/uid-20196318-id-2420884.html" target="_blank" rel="external">http://blog.chinaunix.net/uid-20196318-id-2420884.html</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2016/01/12/mq/4.Kafka系列之入门/" data-id="cijzzpv9n008f1cfst97zwes4" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/kafka/">kafka</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/mq/">mq</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-docker/6.docker系列之数据卷" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2016/01/10/docker/6.docker系列之数据卷/" class="article-date">
  <time datetime="2016-01-09T22:00:00.000Z" itemprop="datePublished">2016-01-10</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/docker/">docker</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2016/01/10/docker/6.docker系列之数据卷/">docker系列六之数据卷</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　主要有两种方法来管理docker数据：数据卷和容器中的数据卷</p>
<h2 id="u6570_u636E_u5377"><a href="#u6570_u636E_u5377" class="headerlink" title="数据卷"></a>数据卷</h2><p>　　数据卷是在一个或多个容器内指定数据卷，并且绕过Union File System来持续提供一些有用的特性和共享数据。<br>　　1. 数据卷之间可以共享或重用容器<br>　　2. 可以直接更改数据卷<br>　　3. 更改数据卷不会被容器镜像当成更新<br>　　4. 体积不变一直到容器不使用它们</p>
<h2 id="u6570_u636E_u5377_u64CD_u4F5C"><a href="#u6570_u636E_u5377_u64CD_u4F5C" class="headerlink" title="数据卷操作"></a>数据卷操作</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#添加数据卷</span></span><br><span class="line"><span class="comment">#在容器内部创建一个新的卷/webapp</span></span><br><span class="line">$ docker run <span class="operator">-d</span> -P --name web -v /webapp training/webapp python app.py</span><br><span class="line"><span class="comment">#可以在Dockerfile中使用VOLUME指令来给创建的镜像添加一个或多个卷。</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#挂载主机目录作为卷</span></span><br><span class="line"><span class="comment">#挂载本地目录/src/webapp到容器的/ot/webapp目录</span></span><br><span class="line">$ docker run <span class="operator">-d</span> -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py</span><br><span class="line"><span class="comment">#开发测试，日志打印非常有用</span></span><br><span class="line"><span class="comment">#主机上的目录必须是绝对路径，如果目录不存在docker会自动创建它</span></span><br><span class="line"><span class="comment">#注意：不可以在Dockerfile中，因为Dockerfile的便携性和移植性，作为主机目录，其性质可能使依赖这个目录的所有主机都无法工作。</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#docker默认情况下是对卷有读写权限，添加ro选项来限制它只读</span></span><br><span class="line">$ docker run <span class="operator">-d</span> -P --name web -v /src/webapp:/opt/webapp:ro training/webapp python app.py</span><br></pre></td></tr></table></figure>
<h2 id="Dockerfile_u521B_u5EFA_u6570_u636E_u5377"><a href="#Dockerfile_u521B_u5EFA_u6570_u636E_u5377" class="headerlink" title="Dockerfile创建数据卷"></a>Dockerfile创建数据卷</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#创建Dockerfile文件</span></span><br><span class="line">FROM docker.io/centos:latest</span><br><span class="line">MAINTAINER shihuacai&lt;shihuacai1989@<span class="number">126</span>.com&gt;</span><br><span class="line"><span class="comment">#镜像启动后会创建两个目录/opt/volume1/ /opt/volume2/</span></span><br><span class="line">VOLUME [<span class="string">"/opt/volume1/"</span>,<span class="string">"/opt/volume2/"</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment">#创建数据卷镜像</span></span><br><span class="line">docker build -t shihuacai/volume .</span><br><span class="line"></span><br><span class="line"><span class="comment">#运行镜像，创建容器Volume_Container</span></span><br><span class="line">docker run -i -t --name Volume_Container shihuacai/volume /bin/bash</span><br><span class="line"></span><br><span class="line"><span class="comment">#在容器中查看数据卷目录</span></span><br><span class="line">[root@c536df4b84c9 /]<span class="comment"># cd /opt</span></span><br><span class="line">[root@c536df4b84c9 opt]<span class="comment"># ls</span></span><br><span class="line">volume1  volume2</span><br><span class="line"></span><br><span class="line"><span class="comment">#向数据卷目录中创建文件并写入数据，结果如下</span></span><br><span class="line">[root@c536df4b84c9 opt]<span class="comment"># cat volume1/readme.txt</span></span><br><span class="line">测试数据</span><br><span class="line">[root@c536df4b84c9 opt]<span class="comment"># cat volume2/readme.txt</span></span><br><span class="line">xxx</span><br><span class="line">yyy</span><br><span class="line"></span><br><span class="line"><span class="comment">#退出容器，启动另一个镜像，命名为centosTest，并挂载数据卷容器Volume_Container</span></span><br><span class="line">docker run -i -t --volumes-from Volume_Container --name centosTest centos /bin/bash</span><br><span class="line"></span><br><span class="line"><span class="comment">#查看容器centosTest中数据卷目录的文件数据</span></span><br><span class="line">[root@af45ba0a0ff2 /]<span class="comment"># cd /opt</span></span><br><span class="line">[root@af45ba0a0ff2 opt]<span class="comment"># ll</span></span><br><span class="line">volume1 volume2</span><br><span class="line">[root@af45ba0a0ff2 opt]<span class="comment"># cat volume1/readme.txt</span></span><br><span class="line">测试数据</span><br><span class="line"></span><br><span class="line"><span class="comment">#说明：也可以在启动镜像时，创建数据卷</span></span><br><span class="line">docker run -v /var/volume1 -v /var/volume2 -name Volume_Container centos  /bin/bash</span><br><span class="line"></span><br><span class="line"><span class="comment">#再创建一个容器，挂载 centosTest 中从 Volume_Container 挂载的数据卷</span></span><br><span class="line">docker run -t -i -rm -volumes-from centosTest -name LastApp_Container centos linux_<span class="built_in">command</span></span><br><span class="line"><span class="comment">#即使删除了刚开始的第一个数据卷容器或者中间层的数据卷容器</span></span><br><span class="line"><span class="comment">#只要有其他容器使用数据卷，数据卷都不会被删除的</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#创建数据卷容器volumeHost </span></span><br><span class="line">docker run -i -t -v /usr/<span class="built_in">local</span>/java:/usr/dev --name volumeHost centos /bin/bash</span><br><span class="line"><span class="comment">#停止容器</span></span><br><span class="line">docker stop volumeHost</span><br><span class="line"><span class="comment">#连接数据卷</span></span><br><span class="line">docker run -i -t --volumes-from volumeHost --name tt centos /bin/bash</span><br><span class="line">[root@<span class="number">57</span>fe8cf02df7 dev]<span class="comment"># cd /usr/dev</span></span><br><span class="line">[root@<span class="number">57</span>fe8cf02df7 dev]<span class="comment"># ls -l</span></span><br><span class="line">total <span class="number">294328</span></span><br><span class="line">-rw-r--r--. <span class="number">1</span> root root       <span class="number">628</span> Jun <span class="number">15</span> <span class="number">13</span>:<span class="number">11</span> Dockerfile</span><br><span class="line">drwxr-xr-x. <span class="number">9</span> root root      <span class="number">4096</span> Jun <span class="number">15</span> <span class="number">12</span>:<span class="number">56</span> apache-tomcat-<span class="number">7.0</span>.<span class="number">47</span></span><br><span class="line">-rw-r--r--. <span class="number">1</span> root root <span class="number">142362384</span> Apr <span class="number">15</span> <span class="number">19</span>:<span class="number">06</span> jdk-<span class="number">7</span>u60-linux-x64.tar.gz</span><br><span class="line">-rw-r--r--. <span class="number">1</span> root root <span class="number">159008252</span> Apr <span class="number">15</span> <span class="number">19</span>:<span class="number">06</span> jdk-<span class="number">8</span>u5-linux-x64.tar.gz</span><br><span class="line">drwxr-xr-x. <span class="number">8</span>   <span class="number">10</span>  <span class="number">143</span>      <span class="number">4096</span> May  <span class="number">7</span>  <span class="number">2014</span> jdk1.<span class="number">7.0</span>_60</span><br><span class="line">drwxr-xr-x. <span class="number">8</span>   <span class="number">10</span>  <span class="number">143</span>      <span class="number">4096</span> Mar <span class="number">18</span>  <span class="number">2014</span> jdk1.<span class="number">8.0</span>_05</span><br><span class="line">[root@<span class="number">57</span>fe8cf02df7 dev]<span class="comment"># mkdir test</span></span><br><span class="line">mkdir: cannot create directory <span class="string">'test'</span>: Permission denied</span><br></pre></td></tr></table></figure>
<h2 id="u4F7F_u7528_u6570_u636E_u5377_u5BB9_u5668"><a href="#u4F7F_u7528_u6570_u636E_u5377_u5BB9_u5668" class="headerlink" title="使用数据卷容器"></a>使用数据卷容器</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#创建数据卷容器</span></span><br><span class="line">$ docker run <span class="operator">-d</span> -v /dbdata --name dbdata training/postgres</span><br><span class="line"><span class="comment">#挂载/dbdata卷</span></span><br><span class="line">$ docker run <span class="operator">-d</span> --volumes-from dbdata --name db1 training/postgres</span><br><span class="line">$ docker run <span class="operator">-d</span> --volumes-from dbdata --name db2 training/postgres</span><br><span class="line"><span class="comment">#也可以使用多个--volumes-from参数来将多个数据卷桥接到多个容器中</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#当删除挂载卷的dbdata容器，包括初始化数据容器，或者随后的db1容器和db2容器</span></span><br><span class="line"><span class="comment">#该卷将不会被删除直到没有容器使用该卷</span></span><br></pre></td></tr></table></figure>
<h2 id="u5907_u4EFD_u3001_u6062_u590D_u6570_u636E_u5377"><a href="#u5907_u4EFD_u3001_u6062_u590D_u6570_u636E_u5377" class="headerlink" title="备份、恢复数据卷"></a>备份、恢复数据卷</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#备份</span></span><br><span class="line"><span class="comment">#挂载dbdata卷，并挂载一个本地目录作为/backup卷</span></span><br><span class="line"><span class="comment">#使用tar命令备份dbdata卷的内容到我们的/backup目录下的backup.tar文件中</span></span><br><span class="line">$ docker run --volumes-from dbdata -v $(<span class="built_in">pwd</span>):/backup ubuntu tar cvf /backup/backup.tar /dbdata</span><br><span class="line"></span><br><span class="line"><span class="comment">#恢复</span></span><br><span class="line"><span class="comment">#创建一个新的容器</span></span><br><span class="line">$ docker run -v /dbdata --name dbdata2 ubuntu /bin/bash</span><br><span class="line"><span class="comment">#在新容器的卷中解压备份文件。</span></span><br><span class="line">$ docker run --volumes-from dbdata2 -v $(<span class="built_in">pwd</span>):/backup busybox tar xvf /backup/backup.tar</span><br></pre></td></tr></table></figure>
<h2 id="u53C2_u8003_u8D44_u6599"><a href="#u53C2_u8003_u8D44_u6599" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="/images/docker-summery.html">docker-summery.html</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2016/01/10/docker/6.docker系列之数据卷/" data-id="cijzzpvg200fj1cfsbmu6i1wc" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/docker/">docker</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-docker/5.docker系列之容器连接" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2016/01/10/docker/5.docker系列之容器连接/" class="article-date">
  <time datetime="2016-01-09T21:00:00.000Z" itemprop="datePublished">2016-01-10</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/docker/">docker</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2016/01/10/docker/5.docker系列之容器连接/">docker系列五之容器连接</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　端口映射并不是唯一把docker连接到另一个容器的方法。docker有一个连接系统允许将多个容器连接在一起，共享连接信息。docker连接会创建一个父子关系，其中父容器可以看到子容器的信息。而不需要映射容器的端口</p>
<h2 id="u5BB9_u5668_u547D_u540D"><a href="#u5BB9_u5668_u547D_u540D" class="headerlink" title="容器命名"></a>容器命名</h2><p>　　执行连接时需要容器的名字，当创建一个容器的时候，它都会自动被命名，我们也可以自己命名容器。这种命名提供了两个有用的功能：<br>　　1. 给容器特定的名字使你更容易记住他们，例如：命名web应用程序为web容器。<br>　　2. 它为docker提供一个参考，允许其他容器引用，举例连接web容器到db容器。<br>　　可以使用–name标识来命名容器，如下所示：<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">$ docker run <span class="operator">-d</span> -P --name web training/webapp python app.py</span><br><span class="line"><span class="comment">#查看容器名称</span></span><br><span class="line">$ docker ps <span class="operator">-l</span></span><br><span class="line">CONTAINER ID  IMAGE                  COMMAND        CREATED       STATUS       PORTS                    NAMES</span><br><span class="line">aed84ee21bde  training/webapp:latest python app.py  <span class="number">12</span> hours ago  Up <span class="number">2</span> seconds <span class="number">0.0</span>.<span class="number">0.0</span>:<span class="number">49154</span>-&gt;<span class="number">5000</span>/tcp  web</span><br><span class="line"><span class="comment">#也可以使用docker inspect来返回容器名字。</span></span><br><span class="line">$ docker inspect <span class="operator">-f</span> <span class="string">"&#123;&#123; .Name &#125;&#125;"</span> aed84ee21bde(aed84ee21bde可以替换为web)</span><br><span class="line">/web</span><br><span class="line"><span class="comment">#注意：容器的名称必须是唯一的。这意味着你只能调用一个web容器。</span></span><br><span class="line"><span class="comment">#如果想使用重复的名称来命名容器，需要使用docker rm命令删除以前的容器，在容器停止后删除。</span></span><br></pre></td></tr></table></figure></p>
<h2 id="u5BB9_u5668_u8FDE_u63A5"><a href="#u5BB9_u5668_u8FDE_u63A5" class="headerlink" title="容器连接"></a>容器连接</h2><p>　　连接允许容器之间可见并且安全地进行通信。使用–link创建连接。我们创建一个新容器，这个容器是数据库。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#数据库容器</span></span><br><span class="line">$ docker run <span class="operator">-d</span> --name postgres training/postgres</span><br><span class="line"><span class="comment">#web容器(子容器)，连接postgres容器(父容器)</span></span><br><span class="line">$ docker run <span class="operator">-d</span> -P --name web --link postgres:db training/webapp python app.py</span><br><span class="line"><span class="comment">#--link的形式：--link name:alias</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#查看容器连接.</span></span><br><span class="line">$ docker ps</span><br><span class="line">CONTAINER ID  IMAGE                     COMMAND               CREATED             STATUS             PORTS                    NAMES</span><br><span class="line"><span class="number">349169744</span>e49  training/postgres:latest  su postgres -c <span class="string">'/usr  About a minute ago  Up About a minute  5432/tcp                 db</span><br><span class="line">aed84ee21bde  training/webapp:latest    python app.py         16 hours ago        Up 2 minutes       0.0.0.0:49154-&gt;5000/tcp  db/web,web（最新版本docker只会显示web）</span></span><br></pre></td></tr></table></figure></p>
<p>　　Docker在父容器中开放子容器连接信息有两种方法：1. 环境变量；2. 更新/etc/hosts文件。让我们先看看docker的环境变量。我们运行env命令来查看列表容器的环境变量。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ docker run --rm --name web --link postgres:db training/webapp env</span><br></pre></td></tr></table></figure></p>
<p>　　运行后结果如下：<img src="/images/docker-link.png" alt="docker-link.png"><br>　　我们可以看到docker为我们的数据库容器创建了一系列环境变量。每个前缀变量是DB<em>填充我们指定的别名。如果我们的别名是db1，前缀别名就是DB1</em>。可以使用这些环境变量来配置应用程序连接到数据库db容器。该连接是安全、私有的，只能在web容器和db容器之间通信。可以使用一个父容器连接多个子容器。例如，我们可以有多个web容器连接到我们的db数据库容器。</p>
<h2 id="u53C2_u8003_u8D44_u6599"><a href="#u53C2_u8003_u8D44_u6599" class="headerlink" title="参考资料"></a>参考资料</h2>
      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2016/01/10/docker/5.docker系列之容器连接/" data-id="cijzzpvg700fo1cfsbh007i5m" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/docker/">docker</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-docker/4.docker系列之Swarm" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2016/01/10/docker/4.docker系列之Swarm/" class="article-date">
  <time datetime="2016-01-09T20:00:00.000Z" itemprop="datePublished">2016-01-10</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/docker/">docker</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2016/01/10/docker/4.docker系列之Swarm/">docker系列四之Swarm</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　docker swarm 是 docker 原生的 docker 集群管理工具。swarm现在还处于BETA版本。 它将一组docker-engine当作一个集群来管理，并且提供了 label、schedule、filter 能力 。swarm 保持了 docker 原有 api 的兼容， 我们可以像使用单个节点一样使用 docker 集群。 </p>
<h2 id="u53C2_u8003_u8D44_u6599"><a href="#u53C2_u8003_u8D44_u6599" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="http://docs.docker.com/swarm/" target="_blank" rel="external">http://docs.docker.com/swarm/</a><br><a href="http://docs.docker.com/swarm/api/swarm-api/" target="_blank" rel="external">http://docs.docker.com/swarm/api/swarm-api/</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2016/01/10/docker/4.docker系列之Swarm/" data-id="cijzzpvge00fr1cfs7hw7xdu4" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/docker/">docker</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-docker/3.docker系列之Registry" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2016/01/10/docker/3.docker系列之Registry/" class="article-date">
  <time datetime="2016-01-09T19:00:00.000Z" itemprop="datePublished">2016-01-10</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/docker/">docker</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2016/01/10/docker/3.docker系列之Registry/">docker系列三之Registry</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　docker镜像私服， 类似于maven的私服， 各个开发机器可以从这个镜像服务器拉取或者推送镜像，私服本身本质上也是一个镜像。安装手册：<a href="https://github.com/docker/distribution/blob/master/docs/deploying.md" target="_blank" rel="external">https://github.com/docker/distribution/blob/master/docs/deploying.md</a></p>
<p>1、启动镜像服务<br>    docker run -d –name registry -v /shihuacai/images:/var/lib/registry  -p 5000:5000 –restart=always registry</p>
<p>2、拉取ubuntu镜像<br>    docker pull ubuntu</p>
<p>3、给镜像打标签<br>    docker tag ubuntu myregistrydomain.com:5000/ubuntu</p>
<p>4、将镜像推到镜像服务器<br>    docker push myregistrydomain.com:5000/ubuntu</p>
<p>5、从镜像服务器拉取ubuntu镜像<br>    docker pull myregistrydomain.com:5000/ubuntu</p>
<p>6、镜像服务器需要使用https 以及认证的一些配置，还会涉及到nginx 和 https 证书的配置，这个我没测试，详细的说明都在上面的安装手册里面。</p>
<pre><code class="bash">
</code></pre>
<h2 id="u53C2_u8003_u8D44_u6599"><a href="#u53C2_u8003_u8D44_u6599" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="https://github.com/docker/docker-registry" target="_blank" rel="external">https://github.com/docker/docker-registry</a></p>
<p><a href="http://blog.tankywoo.com/docker/2014/05/08/docker-3-docker-registry.html" target="_blank" rel="external">http://blog.tankywoo.com/docker/2014/05/08/docker-3-docker-registry.html</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2016/01/10/docker/3.docker系列之Registry/" data-id="cijzzpvgh00fu1cfsif2a2owl" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/docker/">docker</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-docker/2.docker系列之制作镜像" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2016/01/10/docker/2.docker系列之制作镜像/" class="article-date">
  <time datetime="2016-01-09T18:00:00.000Z" itemprop="datePublished">2016-01-10</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/docker/">docker</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2016/01/10/docker/2.docker系列之制作镜像/">docker系列二之制作镜像</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　docker提供了两种方式创建新的镜像：1. 从已经创建的容器中更新镜像，并且提交这个镜像；2. 使用Dockerfile指令来创建一个镜像。下面我们先讲述如何更新一个镜像，再讲解如何使用Dockerfile文件创建镜像，包括离线和在线两种模式。</p>
<h2 id="u66F4_u65B0_u955C_u50CF"><a href="#u66F4_u65B0_u955C_u50CF" class="headerlink" title="更新镜像"></a>更新镜像</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#创建容器</span></span><br><span class="line">$ docker run -i -t ubuntu:<span class="number">14.04</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#修改容器</span></span><br><span class="line">root@d49418a895f8:/<span class="comment"># apt-get install mysql-server</span></span><br><span class="line">root@d49418a895f8:/<span class="comment"># apt-get install mysql-client</span></span><br><span class="line">root@d49418a895f8:/<span class="comment"># apt-get install libmysqlclient-dev</span></span><br><span class="line">root@d49418a895f8:/<span class="comment"># exit</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#提交容器</span></span><br><span class="line">$ docker commit -m=<span class="string">"add mysql"</span> <span class="operator">-a</span>=<span class="string">"shihuacai"</span> d49418a895f8 shihuacai/mysql:v1</span><br><span class="line"><span class="number">4</span>f177bd27a9ff0f6dc2a830403925b5360bfe0b93d476f7<span class="built_in">fc</span>3231110e7f71b1c</span><br><span class="line"><span class="comment">#-m标示是允许我们指定提交的信息，-a标示更新作者</span></span><br><span class="line"><span class="comment">#新镜像来自ID为d49418a895f8的容器</span></span><br><span class="line"><span class="comment">#新镜像的用户名：shihuacai、镜像名：mysql、标签：v1</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#查看新镜像</span></span><br><span class="line">$ docker images</span><br><span class="line">    REPOSITORY      TAG      IMAGE ID           CREATED          VIRTUAL    SIZE </span><br><span class="line">shihuacai/mysql      v1     f15c8436a2fa   <span class="number">58</span> seconds ago       <span class="number">322.5</span>       MB </span><br><span class="line">...</span><br><span class="line"></span><br><span class="line"><span class="comment"># 推送镜像</span></span><br><span class="line">$ docker push shihuacai/mysql  <span class="comment">#需要先创建仓库shihuacai</span></span><br></pre></td></tr></table></figure>
<h2 id="Dockerfile_u79BB_u7EBF_u5236_u4F5Cjdk_u955C_u50CF"><a href="#Dockerfile_u79BB_u7EBF_u5236_u4F5Cjdk_u955C_u50CF" class="headerlink" title="Dockerfile离线制作jdk镜像"></a>Dockerfile离线制作jdk镜像</h2><p>　　1. 进入centos3目录：/usr/local/java，可以看到有如下文件：<img src="/images/56A1E033419C483A96D662F5B6F64E97.jpg" alt="56A1E033419C483A96D662F5B6F64E97.jpg"><br>　　2. 编写Dockerfile文件<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#Build java jdk container image</span></span><br><span class="line">FROM docker.io/centos:latest</span><br><span class="line">MAINTAINER shihuacai&lt;shihuacai1989@<span class="number">126</span>.com&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment">#set java environment</span></span><br><span class="line">ENV JAVA_HOME /usr/<span class="built_in">local</span>/java/jdk1.<span class="number">7</span></span><br><span class="line">ENV CLASSPATH .:<span class="variable">$JAVA_HOME</span>/lib</span><br><span class="line">ENV PATH <span class="variable">$PATH</span>:<span class="variable">$JAVA_HOME</span>/bin</span><br><span class="line"></span><br><span class="line">RUN mkdir /usr/<span class="built_in">local</span>/java</span><br><span class="line"></span><br><span class="line"><span class="comment">#Copy jdk into image</span></span><br><span class="line">ADD jdk1.<span class="number">7.0</span>_60 /usr/<span class="built_in">local</span>/java/jdk1.<span class="number">7</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#VOLUME 创建一个挂载点用于共享目录</span></span><br><span class="line"><span class="comment">#VOLUME ["&lt;mountpoint&gt;"]</span></span><br><span class="line"><span class="comment">#VOLUME ["/data"]</span></span><br></pre></td></tr></table></figure></p>
<p>　　3. 构建镜像<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#下载centos镜像</span></span><br><span class="line">$ docker pull centos:latest</span><br><span class="line"><span class="comment">#构建镜像</span></span><br><span class="line">$ docker build -t shihuacai/centos-jdk7 .</span><br><span class="line"><span class="comment">#Dockerfile在当前目录下，使用.来指定Dockerfile</span></span><br><span class="line"><span class="comment">#启动镜像</span></span><br><span class="line">$ docker run -i -t --name jdk7 shihuacai/centos-jdk7</span><br></pre></td></tr></table></figure></p>
<h2 id="Dockerfile_u79BB_u7EBF_u5236_u4F5Ctomcat_u955C_u50CF"><a href="#Dockerfile_u79BB_u7EBF_u5236_u4F5Ctomcat_u955C_u50CF" class="headerlink" title="Dockerfile离线制作tomcat镜像"></a>Dockerfile离线制作tomcat镜像</h2><p>　　1. 进入centos3目录：/usr/local/java，可以看到有如下文件：<img src="/images/CA58F7917B31493CA7AD75D773E58ED3.jpg" alt="CA58F7917B31493CA7AD75D773E58ED3.jpg"><br>　　2. 编写Dockerfile文件<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#Build java jdk container image</span></span><br><span class="line">FROM docker.io/centos:latest</span><br><span class="line">MAINTAINER shihuacai&lt;shihuacai1989@<span class="number">126</span>.com&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment">#set java environment</span></span><br><span class="line">ENV JAVA_HOME /usr/<span class="built_in">local</span>/java/jdk1.<span class="number">7</span></span><br><span class="line">ENV CLASSPATH .:<span class="variable">$JAVA_HOME</span>/lib</span><br><span class="line">ENV PATH <span class="variable">$PATH</span>:<span class="variable">$JAVA_HOME</span>/bin</span><br><span class="line"></span><br><span class="line">RUN mkdir /usr/<span class="built_in">local</span>/java</span><br><span class="line"></span><br><span class="line">ADD jdk1.<span class="number">7.0</span>_60 /usr/<span class="built_in">local</span>/java/jdk1.<span class="number">7</span></span><br><span class="line"></span><br><span class="line">RUN mkdir /usr/<span class="built_in">local</span>/tomcat</span><br><span class="line">ADD apache-tomcat-<span class="number">7.0</span>.<span class="number">47</span> /usr/<span class="built_in">local</span>/tomcat</span><br><span class="line">RUN chmod +x /usr/<span class="built_in">local</span>/tomcat/bin/catalina.sh</span><br><span class="line">EXPOSE <span class="number">8080</span></span><br><span class="line">CMD /usr/<span class="built_in">local</span>/tomcat/bin/catalina.sh run</span><br></pre></td></tr></table></figure></p>
<p>　　3. 构建镜像<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#构建镜像</span></span><br><span class="line">$ docker build -t shihuacai/tomcat7 .</span><br><span class="line"><span class="comment">#启动镜像</span></span><br><span class="line">$ docker run -i -t <span class="operator">-d</span> -p <span class="number">8080</span>:<span class="number">8080</span> --name tomcat7 shihuacai/tomcat7</span><br><span class="line"><span class="comment">#访问tomcat: http://192.168.241.131:8080/</span></span><br></pre></td></tr></table></figure></p>
<p>　　4. 推送到仓库<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#登录docker hub</span></span><br><span class="line">$ docker login</span><br><span class="line">Username: shihuacai</span><br><span class="line">Password: </span><br><span class="line">Email: shihuacai1989@<span class="number">126</span>.com</span><br><span class="line"></span><br><span class="line"><span class="comment">#推送到docker hub</span></span><br><span class="line">docker push 镜像</span><br></pre></td></tr></table></figure></p>
<h2 id="Dockerfile_u5728_u7EBF_u5236_u4F5Cjdk_u955C_u50CF"><a href="#Dockerfile_u5728_u7EBF_u5236_u4F5Cjdk_u955C_u50CF" class="headerlink" title="Dockerfile在线制作jdk镜像"></a>Dockerfile在线制作jdk镜像</h2><p>　　下面我们看看通过网络在线下载jdk，制作jdk镜像，这种方式直接copy的地址：<a href="https://github.com/tifayuki/docker-image-java" target="_blank" rel="external">https://github.com/tifayuki/docker-image-java</a><br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">FROM ubuntu:trusty</span><br><span class="line">MAINTAINER Feng Honglin &lt;hfeng@tutum.co&gt;</span><br><span class="line"> </span><br><span class="line"><span class="comment"># Install Oracle Java 7</span></span><br><span class="line">ENV JAVA_VER <span class="number">7</span></span><br><span class="line">ENV JAVA_HOME /usr/lib/jvm/java-<span class="number">7</span>-oracle</span><br><span class="line"> </span><br><span class="line">RUN <span class="built_in">echo</span> <span class="string">'deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main'</span> &gt;&gt; /etc/apt/sources.list &amp;&amp; \</span><br><span class="line">    <span class="built_in">echo</span> <span class="string">'deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main'</span> &gt;&gt; /etc/apt/sources.list &amp;&amp; \</span><br><span class="line">    apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C2518248EEA14886 &amp;&amp; \</span><br><span class="line">    apt-get update &amp;&amp; \</span><br><span class="line">    <span class="built_in">echo</span> oracle-java<span class="variable">$&#123;JAVA_VER&#125;</span>-installer shared/accepted-oracle-license-v1-<span class="number">1</span> select <span class="literal">true</span> | sudo /usr/bin/debconf-set-selections &amp;&amp; \</span><br><span class="line">    apt-get install -y --force-yes --no-install-recommends oracle-java<span class="variable">$&#123;JAVA_VER&#125;</span>-installer oracle-java<span class="variable">$&#123;JAVA_VER&#125;</span>-set-default &amp;&amp; \</span><br><span class="line">    apt-get clean &amp;&amp; \</span><br><span class="line">    rm -rf /var/lib/apt/lists &amp;&amp; \</span><br><span class="line">    rm -rf /var/cache/oracle-jdk<span class="variable">$&#123;JAVA_VER&#125;</span>-installer</span><br></pre></td></tr></table></figure></p>
<p>　　下载地址：<a href="/code/docker-image-java-master.zip">docker-image-java-master.zip</a></p>
<h2 id="Dockerfile_u5728_u7EBF_u5236_u4F5Ctomcat_u955C_u50CF"><a href="#Dockerfile_u5728_u7EBF_u5236_u4F5Ctomcat_u955C_u50CF" class="headerlink" title="Dockerfile在线制作tomcat镜像"></a>Dockerfile在线制作tomcat镜像</h2><p>　　下面我们看看通过网络在线下载tomcat，制作jdk镜像，这种方式直接copy的地址：<a href="https://github.com/tutumcloud/tutum-docker-tomcat.git" target="_blank" rel="external">https://github.com/tutumcloud/tutum-docker-tomcat.git</a><br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">FROM tifayuki/java:<span class="number">7</span></span><br><span class="line">MAINTAINER Feng Honglin &lt;hfeng@tutum.co&gt;</span><br><span class="line"></span><br><span class="line">RUN apt-get update &amp;&amp; \</span><br><span class="line">    apt-get install -yq --no-install-recommends wget pwgen ca-certificates &amp;&amp; \</span><br><span class="line">    apt-get clean &amp;&amp; \</span><br><span class="line">    rm -rf /var/lib/apt/lists/*</span><br><span class="line"></span><br><span class="line">ENV TOMCAT_MAJOR_VERSION <span class="number">8</span></span><br><span class="line">ENV TOMCAT_MINOR_VERSION <span class="number">8.0</span>.<span class="number">11</span></span><br><span class="line">ENV CATALINA_HOME /tomcat</span><br><span class="line"></span><br><span class="line"><span class="comment"># INSTALL TOMCAT</span></span><br><span class="line">RUN wget -q https://archive.apache.org/dist/tomcat/tomcat-<span class="variable">$&#123;TOMCAT_MAJOR_VERSION&#125;</span>/v<span class="variable">$&#123;TOMCAT_MINOR_VERSION&#125;</span>/bin/apache-tomcat-<span class="variable">$&#123;TOMCAT_MINOR_VERSION&#125;</span>.tar.gz &amp;&amp; \</span><br><span class="line">    wget -qO- https://archive.apache.org/dist/tomcat/tomcat-<span class="variable">$&#123;TOMCAT_MAJOR_VERSION&#125;</span>/v<span class="variable">$&#123;TOMCAT_MINOR_VERSION&#125;</span>/bin/apache-tomcat-<span class="variable">$&#123;TOMCAT_MINOR_VERSION&#125;</span>.tar.gz.md5 | md5sum -c - &amp;&amp; \</span><br><span class="line">    tar zxf apache-tomcat-*.tar.gz &amp;&amp; \</span><br><span class="line">    rm apache-tomcat-*.tar.gz &amp;&amp; \</span><br><span class="line">    mv apache-tomcat* tomcat</span><br><span class="line"></span><br><span class="line">ADD create_tomcat_admin_user.sh /create_tomcat_admin_user.sh</span><br><span class="line">ADD run.sh /run.sh</span><br><span class="line">RUN chmod +x /*.sh</span><br><span class="line"></span><br><span class="line">EXPOSE <span class="number">8080</span></span><br><span class="line">CMD [<span class="string">"/run.sh"</span>]</span><br></pre></td></tr></table></figure></p>
<p>　　所需的create_tomcat_admin_user.sh如下：<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="shebang">#!/bin/bash</span><br><span class="line"> </span></span><br><span class="line"><span class="keyword">if</span> [ <span class="operator">-f</span> /.tomcat_admin_created ]; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"Tomcat 'admin' user already created"</span></span><br><span class="line">    <span class="built_in">exit</span> <span class="number">0</span></span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"> </span><br><span class="line"><span class="comment">#generate password</span></span><br><span class="line">PASS=<span class="variable">$&#123;TOMCAT_PASS:-$(pwgen -s 12 1)&#125;</span></span><br><span class="line">_word=$( [ <span class="variable">$&#123;TOMCAT_PASS&#125;</span> ] &amp;&amp; <span class="built_in">echo</span> <span class="string">"preset"</span> || <span class="built_in">echo</span> <span class="string">"random"</span> )</span><br><span class="line"> </span><br><span class="line"><span class="built_in">echo</span> <span class="string">"=&gt; Creating and admin user with a <span class="variable">$&#123;_word&#125;</span> password in Tomcat"</span></span><br><span class="line">sed -i -r <span class="string">'s/&lt;\/tomcat-users&gt;//'</span> <span class="variable">$&#123;CATALINA_HOME&#125;</span>/conf/tomcat-users.xml</span><br><span class="line"><span class="built_in">echo</span> <span class="string">'&lt;role rolename="manager-gui"/&gt;'</span> &gt;&gt; <span class="variable">$&#123;CATALINA_HOME&#125;</span>/conf/tomcat-users.xml</span><br><span class="line"><span class="built_in">echo</span> <span class="string">'&lt;role rolename="manager-script"/&gt;'</span> &gt;&gt; <span class="variable">$&#123;CATALINA_HOME&#125;</span>/conf/tomcat-users.xml</span><br><span class="line"><span class="built_in">echo</span> <span class="string">'&lt;role rolename="manager-jmx"/&gt;'</span> &gt;&gt; <span class="variable">$&#123;CATALINA_HOME&#125;</span>/conf/tomcat-users.xml</span><br><span class="line"><span class="built_in">echo</span> <span class="string">'&lt;role rolename="admin-gui"/&gt;'</span> &gt;&gt; <span class="variable">$&#123;CATALINA_HOME&#125;</span>/conf/tomcat-users.xml</span><br><span class="line"><span class="built_in">echo</span> <span class="string">'&lt;role rolename="admin-script"/&gt;'</span> &gt;&gt; <span class="variable">$&#123;CATALINA_HOME&#125;</span>/conf/tomcat-users.xml</span><br><span class="line"><span class="built_in">echo</span> <span class="string">"&lt;user username=\"admin\" password=\"<span class="variable">$&#123;PASS&#125;</span>\" roles=\"manager-gui,manager-script,manager-jmx,admin-gui, admin-script\"/&gt;"</span> &gt;&gt; <span class="variable">$&#123;CATALINA_HOME&#125;</span>/conf/tomcat-users.xml</span><br><span class="line"><span class="built_in">echo</span> <span class="string">'&lt;/tomcat-users&gt;'</span> &gt;&gt; <span class="variable">$&#123;CATALINA_HOME&#125;</span>/conf/tomcat-users.xml </span><br><span class="line"><span class="built_in">echo</span> <span class="string">"=&gt; Done!"</span></span><br><span class="line">touch /.tomcat_admin_created</span><br><span class="line"> </span><br><span class="line"><span class="built_in">echo</span> <span class="string">"========================================================================"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"You can now configure to this Tomcat server using:"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">""</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"    admin:<span class="variable">$&#123;PASS&#125;</span>"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">""</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"========================================================================"</span></span><br></pre></td></tr></table></figure></p>
<p>run.sh<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="shebang">#!/bin/bash</span><br><span class="line"> </span></span><br><span class="line"><span class="keyword">if</span> [ ! <span class="operator">-f</span> /.tomcat_admin_created ]; <span class="keyword">then</span></span><br><span class="line">    /create_tomcat_admin_user.sh</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"> </span><br><span class="line"><span class="built_in">exec</span> <span class="variable">$&#123;CATALINA_HOME&#125;</span>/bin/catalina.sh run</span><br></pre></td></tr></table></figure></p>
<p>　　下载地址：<a href="/code/tutum-docker-tomcat-master.zip">tutum-docker-tomcat-master.zip</a></p>
<h2 id="u5236_u4F5Cnodejs_u955C_u50CF"><a href="#u5236_u4F5Cnodejs_u955C_u50CF" class="headerlink" title="制作nodejs镜像"></a>制作nodejs镜像</h2><h5 id="1-__u521B_u5EFAnodejs_u5E94_u7528"><a href="#1-__u521B_u5EFAnodejs_u5E94_u7528" class="headerlink" title="1. 创建nodejs应用"></a>1. 创建nodejs应用</h5><p>　　首先在目录src下创建package.json来描述应用程序和依赖关系<br><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    "<span class="attribute">name</span>": <span class="value"><span class="string">"docker-centos-hello"</span></span>, </span><br><span class="line">    "<span class="attribute">private</span>": <span class="value"><span class="literal">true</span></span>, </span><br><span class="line">    "<span class="attribute">version</span>": <span class="value"><span class="string">"0.0.1"</span></span>, </span><br><span class="line">    "<span class="attribute">description</span>": <span class="value"><span class="string">"Node.js Hello world app on CentOS using docker"</span></span>, </span><br><span class="line">    "<span class="attribute">author</span>": <span class="value"><span class="string">"Daniel Gasienica &lt;daniel@gasienica.ch&gt;"</span></span>, </span><br><span class="line">    "<span class="attribute">dependencies</span>": <span class="value">&#123;</span><br><span class="line">        "<span class="attribute">express</span>": <span class="value"><span class="string">"3.2.4"</span></span><br><span class="line">    </span>&#125;</span><br><span class="line"></span>&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　然后创建一个index.js文件，使用Express.js框架来做一个web应用程序，监听8080端口。<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> express = <span class="built_in">require</span>(<span class="string">'express'</span>);</span><br><span class="line"><span class="keyword">var</span> PORT = <span class="number">8080</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> app = express();</span><br><span class="line">app.get(<span class="string">'/'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">req, res</span>) </span>&#123;</span><br><span class="line">    res.send(<span class="string">'Hello world\n'</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">app.listen(PORT);</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'Running on http://localhost:'</span> + PORT);</span><br></pre></td></tr></table></figure></p>
<h5 id="2-__u7F16_u5199Dockerfile_u6587_u4EF6"><a href="#2-__u7F16_u5199Dockerfile_u6587_u4EF6" class="headerlink" title="2. 编写Dockerfile文件"></a>2. 编写Dockerfile文件</h5><p>　　在src目录下创建一个文件：Dockerfile<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 定义构建镜像的顶级镜像</span></span><br><span class="line">FROM    centos:<span class="number">6.4</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 在Centos镜像中安装Node.js</span></span><br><span class="line">RUN rpm -Uvh http://download.fedoraproject.org/pub/epel/<span class="number">6</span>/i386/epel-release-<span class="number">6</span>-<span class="number">8</span>.noarch.rpm</span><br><span class="line"><span class="comment"># Node.js运行应用程序需要使用npm安装package.json中定义的依赖关系</span></span><br><span class="line">RUN yum install -y npm</span><br><span class="line"></span><br><span class="line"><span class="comment"># 将应用程序源代码添加到Docker镜像中</span></span><br><span class="line">ADD . /src</span><br><span class="line"><span class="comment"># 使用npm安装应用程序依赖</span></span><br><span class="line">RUN <span class="built_in">cd</span> /src; npm install</span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用EXPOSE指令将8080端口做docker进程映射</span></span><br><span class="line">EXPOSE  <span class="number">8080</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用CMD定义运行时的node服务和应用src/index.js的路径</span></span><br><span class="line">CMD [<span class="string">"node"</span>, <span class="string">"/src/index.js"</span>]</span><br></pre></td></tr></table></figure></p>
<h5 id="3-__u8BBF_u95EE_u5E94_u7528"><a href="#3-__u8BBF_u95EE_u5E94_u7528" class="headerlink" title="3. 访问应用"></a>3. 访问应用</h5><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#创建镜像</span></span><br><span class="line">$ docker build -t shihuacai/centos-node-hello .</span><br><span class="line"></span><br><span class="line"><span class="comment">#运行镜像，-p参数绑定一个公共端口到私有容器端口上</span></span><br><span class="line">$ docker run -p <span class="number">49160</span>:<span class="number">8080</span> <span class="operator">-d</span> shihuacai/centos-node-hello</span><br><span class="line"></span><br><span class="line"><span class="comment">#访问应用</span></span><br><span class="line">curl -i localhost:<span class="number">49160</span></span><br></pre></td></tr></table></figure>
<h2 id="u5236_u4F5Cssh_u3001tomcat_u955C_u50CF"><a href="#u5236_u4F5Cssh_u3001tomcat_u955C_u50CF" class="headerlink" title="制作ssh、tomcat镜像"></a>制作ssh、tomcat镜像</h2><p>　　编写Dockerfile文件<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># VERSION 0.0.1</span></span><br><span class="line">FROM ubuntu</span><br><span class="line">MAINTAINER yongboy <span class="string">"yongboy@gmail.com"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 更新源，安装ssh server</span></span><br><span class="line">RUN <span class="built_in">echo</span> <span class="string">"deb http://archive.ubuntu.com/ubuntu precise main universe"</span>&gt; /etc/apt/sources.list</span><br><span class="line">RUN apt-get update</span><br><span class="line">RUN apt-get install -y openssh-server</span><br><span class="line">RUN mkdir -p /var/run/sshd</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置root ssh远程登录密码为123456</span></span><br><span class="line">RUN <span class="built_in">echo</span> <span class="string">"root:123456"</span> | chpasswd </span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加orache java7源，一次性安装vim，wget，curl，java7，tomcat7等必备软件</span></span><br><span class="line">RUN apt-get install python-software-properties</span><br><span class="line">RUN add-apt-repository ppa:webupd8team/java</span><br><span class="line">RUN apt-get update</span><br><span class="line">RUN apt-get install -y vim wget curl oracle-java7-installer tomcat7</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置JAVA_HOME环境变量</span></span><br><span class="line">RUN update-alternatives --display java</span><br><span class="line">RUN <span class="built_in">echo</span> <span class="string">"JAVA_HOME=/usr/lib/jvm/java-7-oracle"</span> &gt;&gt; /etc/environment</span><br><span class="line">RUN <span class="built_in">echo</span> <span class="string">"JAVA_HOME=/usr/lib/jvm/java-7-oracle"</span> &gt;&gt; /etc/default/tomcat7</span><br><span class="line"></span><br><span class="line"><span class="comment"># 容器需要开放SSH 22端口</span></span><br><span class="line">EXPOSE <span class="number">22</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 容器需要开放Tomcat 8080端口</span></span><br><span class="line">EXPOSE <span class="number">8080</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置Tomcat7初始化运行，SSH终端服务器作为后台运行</span></span><br><span class="line">ENTRYPOINT service tomcat7 start &amp;&amp; /usr/sbin/sshd -D</span><br></pre></td></tr></table></figure></p>
<p>需要注意：<br>　　1. ENTRYPOINT，表示镜像在初始化时需要执行的命令，不可被重写覆盖，需谨记<br>　　2. CMD，表示镜像运行默认参数，可被重写覆盖<br>　　3. ENTRYPOINT/CMD都只能在文件中存在一次，并且最后一个生效，存在多个，只有最后一个生效，其它无效！需要初始化运行多个命令，彼此之间可以使用 &amp;&amp; 隔开，但最后一个须要为无限运行的命令，需切记！<br>　　在Docker daemon模式下，无论是使用ENTRYPOINT，还是CMD，Dockerfile中最后的命令，一定要是当前进程需要一直运行的，才能够防容器退出。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 无效</span></span><br><span class="line">$ ENTRYPOINT service tomcat7 start <span class="comment">#运行几秒钟之后，容器就会退出</span></span><br><span class="line">$ CMD service tomcat7 start <span class="comment">#运行几秒钟之后，容器就会退出</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 这样有效</span></span><br><span class="line">$ ENTRYPOINT service tomcat7 start &amp;&amp; tail <span class="operator">-f</span> /var/lib/tomcat7/logs/catalina.out</span><br><span class="line"><span class="comment"># 或者</span></span><br><span class="line">$ CMD service tomcat7 start &amp;&amp; tail <span class="operator">-f</span> /var/lib/tomcat7/logs/catalina.out</span><br><span class="line">这样也有效：</span><br><span class="line">$ ENTRYPOINT [<span class="string">"/usr/sbin/sshd"</span>]</span><br><span class="line">$ CMD [<span class="string">"-D"</span>]</span><br></pre></td></tr></table></figure></p>
<p>　　在Dockerfile中，若没有使用ENTRYPOINT/CMD指令，若运行多个命令，可以这样做：<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run <span class="operator">-d</span> -p <span class="number">22</span> -p <span class="number">8080</span> yongboy/java7 /bin/sh -c <span class="string">"service tomcat7 start &amp;&amp; /usr/sbin/sshd -D"</span></span><br></pre></td></tr></table></figure></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2016/01/10/docker/2.docker系列之制作镜像/" data-id="cijzzpvgl00fx1cfsxuu7lfg9" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/docker/">docker</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-docker/1.docker系列之简介" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2016/01/10/docker/1.docker系列之简介/" class="article-date">
  <time datetime="2016-01-09T17:00:00.000Z" itemprop="datePublished">2016-01-10</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/docker/">docker</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2016/01/10/docker/1.docker系列之简介/">docker系列一之简介</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　Docker 是一个开源的应用容器引擎，让开发者可以打包他们的应用以及依赖包到一个可移植的容器中，然后发布到任何流行的Linux机器上，也可以实现虚拟化。容器是完全使用沙箱机制，相互之间不会有任何接口（类似 iPhone 的 app）。几乎没有性能开销,可以很容易地在机器和数据中心中运行。最重要的是,他们不依赖于任何语言、框架包括系统。</p>
<h2 id="u5B89_u88C5_u914D_u7F6E"><a href="#u5B89_u88C5_u914D_u7F6E" class="headerlink" title="安装配置"></a>安装配置</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#centos中安装docker:</span></span><br><span class="line">yum -y install docker</span><br><span class="line"><span class="comment">#说明：centos7中yum可能提示错误：another app is currently holding the yum lock;waiting for it to exit</span></span><br><span class="line"><span class="comment">#此时可能是系统自动升级正在运行，yum在锁定状态中。可以通过强制关掉yum进程：#rm -f /var/run/yum.pid</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#确保docker版本在1.3.2以上</span></span><br><span class="line">docker -v</span><br><span class="line"></span><br><span class="line"><span class="comment">#配置国内镜像源：</span></span><br><span class="line">sed -i <span class="string">'s|OPTIONS=|OPTIONS=--registry-mirror=http://348ff8dc.m.daocloud.io |g'</span> /etc/sysconfig/docker service docker restart</span><br></pre></td></tr></table></figure>
<h2 id="u5E38_u7528_u64CD_u4F5C"><a href="#u5E38_u7528_u64CD_u4F5C" class="headerlink" title="常用操作"></a>常用操作</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#下载镜像</span></span><br><span class="line">$ docker pull ubuntu</span><br><span class="line"></span><br><span class="line"><span class="comment">#查看镜像</span></span><br><span class="line">$ docker images</span><br><span class="line">REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE</span><br><span class="line">docker.io/ubuntu    latest              <span class="number">07</span>f8e8c5e660        <span class="number">3</span> weeks ago         <span class="number">188.3</span> MB</span><br><span class="line"></span><br><span class="line"><span class="comment">#运行镜像</span></span><br><span class="line">$ docker run -i -t ubuntu /bin/bash</span><br><span class="line"><span class="comment">#镜像运行后成为容器，执行后停留在容器中，可以在容器中执行各种linux命令</span></span><br><span class="line"><span class="comment">#输入exit退出容器，不带参数 -i -t，运行完成之后直接退出容器</span></span><br><span class="line">$ docker run ubuntu /bin/<span class="built_in">echo</span> <span class="string">'world'</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#停止容器</span></span><br><span class="line">$ docker stop insane_babbage <span class="comment">#docker会在容器启动的时候自动给容器命名</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#重启容器</span></span><br><span class="line"><span class="comment">#启动已停止的容器</span></span><br><span class="line">$ docker start nostalgic_morse</span><br><span class="line"><span class="comment">#重启正在运行的容器</span></span><br><span class="line">$ docker restart nostalgic_morse</span><br><span class="line"></span><br><span class="line"><span class="comment">#删除容器</span></span><br><span class="line">$ docker rm insane_babbage  <span class="comment">#必须先停止容器在删除，防止意外删除正在运行容器</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#删除镜像</span></span><br><span class="line">$ docker rmi ubuntu  <span class="comment">#需要先删除容器</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#查看容器内进程</span></span><br><span class="line">$ docker top nostalgic_morse</span><br><span class="line">PID                 USER                COMMAND</span><br><span class="line"><span class="number">854</span>                 root                python app.py</span><br><span class="line"></span><br><span class="line"><span class="comment">#守护进程</span></span><br><span class="line"><span class="comment">#以守护进程的模式运行镜像，并让其一直输出"hello word"</span></span><br><span class="line"><span class="comment">#-d标识告诉docker以后台模式运行容器</span></span><br><span class="line">$ docker run <span class="operator">-d</span> ubuntu:<span class="number">14.04</span> /bin/sh -c <span class="string">"while true; do echo hello world; sleep 1; done"</span></span><br><span class="line"><span class="number">1</span>e5535038e285177d5214659a068137486f96ee5c2e85a4ac52dc83f2ebe4147</span><br><span class="line"><span class="comment">#输出的长字符串叫做容器ID，它是容器的唯一标识，我们可以根据容器ID查看"hello word"进程发生了什么。</span></span><br><span class="line"><span class="comment">#注意：容器ID是有点长并且非常的笨拙，稍后我们会看到一个断点的ID,某些方面来说它是容器ID的简化版。</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#查询docker进程的所有容器</span></span><br><span class="line">$ docker ps <span class="comment">#只显示运行中的容器，如果想显示已经停止的容器请-a标示</span></span><br><span class="line">CONTAINER ID  IMAGE         COMMAND               CREATED        STATUS       PORTS NAMES</span><br><span class="line"><span class="number">1</span>e5535038e28  ubuntu:<span class="number">14.04</span>  /bin/sh -c <span class="string">'while tr  2 minutes ago  Up 1 minute        insane_babbage</span><br><span class="line">#返回信息包括：短的容器ID(1e5535038e28)和自动分配的名称(insane_babbage)</span><br><span class="line"># docker ps -l</span><br><span class="line"></span><br><span class="line">#查看容器正在做什么</span><br><span class="line">$ docker logs insane_babbage #也可使用docker logs 1e5535038e28</span><br><span class="line">hello world</span><br><span class="line">hello world</span><br><span class="line">hello world</span><br><span class="line">......</span><br><span class="line"></span><br><span class="line">#查看命令参数</span><br><span class="line">#run命令参数</span><br><span class="line">$ docker run --help</span><br><span class="line">-i, --interactive=false    Keep STDIN open even if not attached  允许我们对容器内的STDIN进行交互</span><br><span class="line">-t, --tty=false            Allocate a pseudo-TTY   在容器内指定一个伪终端或终端</span><br><span class="line">#ps命令参数</span><br><span class="line">$ docker ps --help</span></span><br></pre></td></tr></table></figure>
<h2 id="u8FD0_u884Cweb_u5E94_u7528"><a href="#u8FD0_u884Cweb_u5E94_u7528" class="headerlink" title="运行web应用"></a>运行web应用</h2><p>　　镜像training/webapp被创建后就已经包含了简单的python应用程序环境，首先我们将运行一个python的web应用。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">$ docker run <span class="operator">-d</span> -P training/webapp python app.py</span><br><span class="line"><span class="comment">#如果没有安装training/webapp镜像，会自动从网上下载镜像</span></span><br><span class="line"><span class="comment">#-P通知Docker所需的网络端口映射从主机映射到我们的容器内</span></span><br><span class="line"></span><br><span class="line">$ docker ps <span class="operator">-l</span></span><br><span class="line">CONTAINER ID  IMAGE                   COMMAND       CREATED        STATUS        PORTS                    NAMES</span><br><span class="line">bc533791f3f5  training/webapp:latest  python app.py <span class="number">5</span> seconds ago  Up <span class="number">2</span> seconds  <span class="number">0.0</span>.<span class="number">0.0</span>:<span class="number">49155</span>-&gt;<span class="number">5000</span>/tcp  nostalgic_morse</span><br><span class="line"><span class="comment">#输出多了一列PORTS</span></span><br><span class="line"><span class="comment">#通过使用-P标示，实现主机端口 =&gt; docker端口，此时docker开放了5000端口（默认Phtyon端口）映射到主机端口49155上</span></span><br><span class="line"><span class="comment">#打开浏览器访问：192.168.241.131:49155</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#指定端口</span></span><br><span class="line"><span class="comment">#Docker可以配置绑定网络端口。-P是-p 5000的快捷方式，5000为docker端口</span></span><br><span class="line"><span class="comment">#-p 5000可以使端口5000映射到外部的端口</span></span><br><span class="line"><span class="comment">#也可以指定-p标示来指定端口（可以不在默认外部端口范围内）</span></span><br><span class="line">$ docker run <span class="operator">-d</span> -p <span class="number">5001</span>:<span class="number">5000</span> training/webapp python app.py</span><br><span class="line"><span class="comment">#5001:5000 =&gt; 外部端口:内部端口</span></span><br><span class="line"><span class="comment">#打开浏览器访问：192.168.241.131:5001</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#网络端口快捷方式</span></span><br><span class="line">$ docker port nostalgic_morse <span class="number">5000</span></span><br><span class="line"><span class="number">0.0</span>.<span class="number">0.0</span>:<span class="number">49155</span>  <span class="comment">#容器端口5000映射到主机的49155端口</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#程序日志</span></span><br><span class="line">$ docker logs nostalgic_morse</span><br><span class="line"><span class="comment">#标示-f将在docker log命令中使用tail -f来查看容器标准输出。</span></span><br><span class="line"><span class="comment">#刷新浏览器，注意5000端口应用程序的日志变化。</span></span><br><span class="line">$ docker logs <span class="operator">-f</span> nostalgic_morse</span><br></pre></td></tr></table></figure></p>
<h2 id="u5BB9_u5668_u5E95_u5C42_u4FE1_u606F"><a href="#u5BB9_u5668_u5E95_u5C42_u4FE1_u606F" class="headerlink" title="容器底层信息"></a>容器底层信息</h2><p>　　使用docker inspect来查看Docker的底层信息，它会返回一个JSON文件记录docker容器的配置和状态信息。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">$ docker inspect nostalgic_morse</span><br><span class="line">[&#123;</span><br><span class="line">    <span class="string">"ID"</span>: <span class="string">"bc533791f3f500b280a9626688bc79e342e3ea0d528efe3a86a51ecb28ea20"</span>,</span><br><span class="line">    <span class="string">"Created"</span>: <span class="string">"2014-05-26T05:52:40.808952951Z"</span>,</span><br><span class="line">    <span class="string">"Path"</span>: <span class="string">"python"</span>,</span><br><span class="line">    <span class="string">"Args"</span>: [</span><br><span class="line">       <span class="string">"app.py"</span></span><br><span class="line">    ],</span><br><span class="line">    <span class="string">"Config"</span>: &#123;</span><br><span class="line">       <span class="string">"Hostname"</span>: <span class="string">"bc533791f3f5"</span>,</span><br><span class="line">       <span class="string">"Domainname"</span>: <span class="string">""</span>,</span><br><span class="line">       <span class="string">"User"</span>: <span class="string">""</span>,</span><br><span class="line">. . .</span><br><span class="line"><span class="comment">#只返回容器的IP地址：</span></span><br><span class="line">$ docker inspect <span class="operator">-f</span> <span class="string">'&#123;&#123; .NetworkSettings.IPAddress &#125;&#125;'</span> nostalgic_morse</span><br><span class="line"><span class="number">172.17</span>.<span class="number">0.5</span></span><br></pre></td></tr></table></figure></p>
<p>　　完整的信息如下图所示：<img src="/images/docker-container-info.png" alt="docker-container-info.png"></p>
<h2 id="u53C2_u8003_u94FE_u63A5"><a href="#u53C2_u8003_u94FE_u63A5" class="headerlink" title="参考链接"></a>参考链接</h2><p><a href="http://www.widuu.com/chinese_docker/index.html" target="_blank" rel="external">http://www.widuu.com/chinese_docker/index.html</a><br><a href="https://github.com/widuu/chinese_docker" target="_blank" rel="external">https://github.com/widuu/chinese_docker</a><br><a href="http://dockerone.com/article/160" target="_blank" rel="external">http://dockerone.com/article/160</a><br><a href="http://cloud.51cto.com/art/201501/463536.htm" target="_blank" rel="external">http://cloud.51cto.com/art/201501/463536.htm</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2016/01/10/docker/1.docker系列之简介/" data-id="cijzzpvgp00g01cfs4ilxyapn" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/docker/">docker</a></li></ul>

    </footer>
  </div>
  
</article>


  
  
    <nav id="page-nav">
      <a class="extend prev" rel="prev" href="/page/4/">&laquo; Prev</a><a class="page-number" href="/">1</a><span class="space">&hellip;</span><a class="page-number" href="/page/3/">3</a><a class="page-number" href="/page/4/">4</a><span class="page-number current">5</span><a class="page-number" href="/page/6/">6</a><a class="page-number" href="/page/7/">7</a><span class="space">&hellip;</span><a class="page-number" href="/page/15/">15</a><a class="extend next" rel="next" href="/page/6/">Next &raquo;</a>
    </nav>
  
</section>
        
          <aside id="sidebar">
  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Categories</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/cache/">cache</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/database/">database</a><span class="category-list-count">13</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/docker/">docker</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/gis/">gis</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/git/">git</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/go/">go</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/gradle/">gradle</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/groovy/">groovy</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/hadoop/">hadoop</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/java/">java</a><span class="category-list-count">18</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/linux/">linux</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/log/">log</a><span class="category-list-count">11</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mongodb/">mongodb</a><span class="category-list-count">14</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mq/">mq</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mybatis/">mybatis</a><span class="category-list-count">9</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/netty/">netty</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nginx/">nginx</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nio/">nio</a><span class="category-list-count">19</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nodejs/">nodejs</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/redis/">redis</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/rpc/">rpc</a><span class="category-list-count">14</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/spring/">spring</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/tomcat/">tomcat</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/zookeeper/">zookeeper</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/杂项/">杂项</a><span class="category-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tags</h3>
    <div class="widget">
      <ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/aop/">aop</a><span class="tag-list-count">8</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/aspectj/">aspectj</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/cache/">cache</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/classloader/">classloader</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/common-loggings/">common-loggings</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/commonjs/">commonjs</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/database/">database</a><span class="tag-list-count">10</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/docker/">docker</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/dubbo/">dubbo</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/fastdfs/">fastdfs</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gclib/">gclib</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/geohash/">geohash</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gis/">gis</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/git/">git</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/go/">go</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gradle/">gradle</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/groovy/">groovy</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hadoop/">hadoop</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hessisan/">hessisan</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/java/">java</a><span class="tag-list-count">48</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/javassist/">javassist</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/kafka/">kafka</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/linux/">linux</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/log/">log</a><span class="tag-list-count">11</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/log4j/">log4j</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/logback/">logback</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/map/">map</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/memecached/">memecached</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mina/">mina</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mongodb/">mongodb</a><span class="tag-list-count">14</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mq/">mq</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mqtt/">mqtt</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mybatis/">mybatis</a><span class="tag-list-count">9</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/netty/">netty</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nginx/">nginx</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nio/">nio</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nodejs/">nodejs</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/postgresql/">postgresql</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/protobuf/">protobuf</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/proxy/">proxy</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/push/">push</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/rabbitmq/">rabbitmq</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/redis/">redis</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/rpc/">rpc</a><span class="tag-list-count">14</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/sitemesh/">sitemesh</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/sld/">sld</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/slf4j/">slf4j</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/socket/">socket</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spatialite-for-android/">spatialite for android</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spi/">spi</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spring/">spring</a><span class="tag-list-count">13</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/tomcat/">tomcat</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/transaction/">transaction</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/web/">web</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/xSocket/">xSocket</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zbus/">zbus</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zookeeper/">zookeeper</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/数据结构/">数据结构</a><span class="tag-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tag Cloud</h3>
    <div class="widget tagcloud">
      <a href="/tags/aop/" style="font-size: 15.38px;">aop</a> <a href="/tags/aspectj/" style="font-size: 11.54px;">aspectj</a> <a href="/tags/cache/" style="font-size: 11.54px;">cache</a> <a href="/tags/classloader/" style="font-size: 10px;">classloader</a> <a href="/tags/common-loggings/" style="font-size: 10px;">common-loggings</a> <a href="/tags/commonjs/" style="font-size: 12.31px;">commonjs</a> <a href="/tags/database/" style="font-size: 16.92px;">database</a> <a href="/tags/docker/" style="font-size: 13.85px;">docker</a> <a href="/tags/dubbo/" style="font-size: 10px;">dubbo</a> <a href="/tags/fastdfs/" style="font-size: 10px;">fastdfs</a> <a href="/tags/gclib/" style="font-size: 10.77px;">gclib</a> <a href="/tags/geohash/" style="font-size: 10px;">geohash</a> <a href="/tags/gis/" style="font-size: 10px;">gis</a> <a href="/tags/git/" style="font-size: 10.77px;">git</a> <a href="/tags/go/" style="font-size: 10px;">go</a> <a href="/tags/gradle/" style="font-size: 10px;">gradle</a> <a href="/tags/groovy/" style="font-size: 10px;">groovy</a> <a href="/tags/hadoop/" style="font-size: 10px;">hadoop</a> <a href="/tags/hessisan/" style="font-size: 11.54px;">hessisan</a> <a href="/tags/java/" style="font-size: 20px;">java</a> <a href="/tags/javassist/" style="font-size: 10px;">javassist</a> <a href="/tags/kafka/" style="font-size: 11.54px;">kafka</a> <a href="/tags/linux/" style="font-size: 12.31px;">linux</a> <a href="/tags/log/" style="font-size: 17.69px;">log</a> <a href="/tags/log4j/" style="font-size: 12.31px;">log4j</a> <a href="/tags/logback/" style="font-size: 13.08px;">logback</a> <a href="/tags/map/" style="font-size: 10px;">map</a> <a href="/tags/memecached/" style="font-size: 10.77px;">memecached</a> <a href="/tags/mina/" style="font-size: 13.08px;">mina</a> <a href="/tags/mongodb/" style="font-size: 19.23px;">mongodb</a> <a href="/tags/mq/" style="font-size: 13.85px;">mq</a> <a href="/tags/mqtt/" style="font-size: 10.77px;">mqtt</a> <a href="/tags/mybatis/" style="font-size: 16.15px;">mybatis</a> <a href="/tags/netty/" style="font-size: 10px;">netty</a> <a href="/tags/nginx/" style="font-size: 11.54px;">nginx</a> <a href="/tags/nio/" style="font-size: 13.08px;">nio</a> <a href="/tags/nodejs/" style="font-size: 10px;">nodejs</a> <a href="/tags/postgresql/" style="font-size: 10.77px;">postgresql</a> <a href="/tags/protobuf/" style="font-size: 10px;">protobuf</a> <a href="/tags/proxy/" style="font-size: 10px;">proxy</a> <a href="/tags/push/" style="font-size: 10px;">push</a> <a href="/tags/rabbitmq/" style="font-size: 11.54px;">rabbitmq</a> <a href="/tags/redis/" style="font-size: 13.85px;">redis</a> <a href="/tags/rpc/" style="font-size: 19.23px;">rpc</a> <a href="/tags/sitemesh/" style="font-size: 10px;">sitemesh</a> <a href="/tags/sld/" style="font-size: 10px;">sld</a> <a href="/tags/slf4j/" style="font-size: 10px;">slf4j</a> <a href="/tags/socket/" style="font-size: 14.62px;">socket</a> <a href="/tags/spatialite-for-android/" style="font-size: 10px;">spatialite for android</a> <a href="/tags/spi/" style="font-size: 10px;">spi</a> <a href="/tags/spring/" style="font-size: 18.46px;">spring</a> <a href="/tags/tomcat/" style="font-size: 10.77px;">tomcat</a> <a href="/tags/transaction/" style="font-size: 10px;">transaction</a> <a href="/tags/web/" style="font-size: 10px;">web</a> <a href="/tags/xSocket/" style="font-size: 14.62px;">xSocket</a> <a href="/tags/zbus/" style="font-size: 10px;">zbus</a> <a href="/tags/zookeeper/" style="font-size: 10.77px;">zookeeper</a> <a href="/tags/数据结构/" style="font-size: 10.77px;">数据结构</a>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/01/">January 2016</a><span class="archive-list-count">67</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/12/">December 2015</a><span class="archive-list-count">81</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/11/">November 2015</a><span class="archive-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recents</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2016/01/30/资料/">(no title)</a>
          </li>
        
          <li>
            <a href="/2016/01/30/java/13.Classloader系列一/">ClassLoader系列一</a>
          </li>
        
          <li>
            <a href="/2016/01/29/hadoop/1.hadoop系列之源码编译/">hadoop系列一之源码编译</a>
          </li>
        
          <li>
            <a href="/2016/01/29/go/1.GO系列之入门/">Go系列一之入门</a>
          </li>
        
          <li>
            <a href="/2016/01/28/tomcat/2.tomcat性能优化/">tomcat性能优化</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2016 John Doe<br>
      Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>
    </div>
    <nav id="mobile-nav">
  
    <a href="/" class="mobile-nav-link">Home</a>
  
    <a href="/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    


<script src="http://libs.baidu.com/jquery/2.0.3/jquery.min.js"></script>


  <link rel="stylesheet" href="/fancybox/jquery.fancybox.css" type="text/css">
  <script src="/fancybox/jquery.fancybox.pack.js" type="text/javascript"></script>


<script src="/js/script.js" type="text/javascript"></script>

  </div>
</body>
</html>